Introduction
Lab book for analyses using hierachal computational modelling to identify parameters that define the best model of learning as it applies to fear conditioning acquisition and extinction using FLARe fear conditioning data. Long abstract, justification and analysis plan found in prelim manuscript here
In short:
Aims
Identify model of learning based on a priori hypotheses that best fits the trajectories of fear relevant learning in our FLARe dataset
- Use all first week data from Validation, app TRT, lab TRT, Pilot, Headphones (n = 223 after exclusions)
- Include Acquisition, extinction (trajectories representing fear learning and treatment)
- Identify parameters that define these trajectories
- e.g. Learnign rate, plateau, first ambiguous trial etc.
Cross validate best fitting model in TEDS data
Are these parameters associated with other emasures of indsividual differences in our datasets?
- Personality (Neuroticism)
- Current anxiety symptoms (GAD-7) - equivalent of baseline symptoms (Chris + Meg analyses)
- Lifetime / trait anxiety (STAI / ASI - FLARe analyses)
- Current depression symptoms (PHQ-9) - equivalent of baseline symptoms (Chris + Meg analyses)
- Interpretation biases (IUS, ASSIQ - FLARe analyses)
- SES (Meg IAPT: benefits, employment etc)
- Gender (Meg analyses)
- Emotion regulation profile (potentially LCA based?)
Impact and relevance
Evidence from both human (Richter et al., 2012) and rodent (Galatzer-Levy, Bonanno, Bush, & LeDoux, 2013) studies suggest that trajectories of how we learn and extinguish fear differ between individuals. Different trajectories of fear and extinction have also been found using fear conditioning studies (e.g. Duits et al., 2016), a good model for the learning of, and treatment for, fear and anxiety disorders. It is likely that these trajectories of fear extinction might predict outcomes in exposure-based cognitive behavioural therapy (Kindt, 2014).
Identifying parameters that predict individual trajectories of fear learning and extinction will enable us to harness fear conditioning data more effectively to aid in understanding mechanisms underlying the development of and treatment for anxiety disorders. With more accurate models of these processes, the potential to use fear conditioning paradigms to predict those most at risk of developing an anxiety disorder, and those who might respond best to exposure-based treatments, greatly improves.
Analysis plan
Define set of a priori models moving from simple to more complex
- Some parameters to include:
- Rate of learning (sometimes with punishment reinforcement)
- Sensitivity to punishment
- Pre-existing anxiety
- SES? Gender?
Run each model and compare fit in FLARe pre TEDS data
- Use Log likelihood and BIC etc.
Select best fitting model
Extract individual data for learning parameters from this model and see what factors best predict it
- Anxiety (if anxiety isnt best as part of the model)
- Interpretation biases
- Tolerance of uncertanty
- Cognitive emotional control
- emotional attentional control
- SES?
- Gender?
Run all models again in FLARe TEDS
- Decide if the same model best fits the data again.
- See if we get similar results from the parameter prediction
Will use a combination of R.Version(3.5.1), RStan (Version 2.18.2, GitRev: 2e1f913d3ca3) and hBayesDM package in R (3.5.1) Ahn, W.-Y., Haines, N., & Zhang, L. (2017). Revealing neuro-computational mechanisms of reinforcement learning and decision-making with the hBayesDM package. Computational Psychiatry, 1, 24-57., which uses RStan
Modelling notes
Intuition
Discussion with Vince Valton and Alex Pike about the best way to fit this model. As the observed outcomes (expectancy ratings) are non binary and are related to eachother (i.e. as you become more likely to select 9, you become less likely to select 1) we should consider each trial for each person for each stimulus as a constantly updating beta distribution. so you might see a pattern like this for the CS+ in acq for example.
So, best model is likely to be one using beta distributions that show the probability distribution for each rating.
We can use sufficient parameters to describe these (i.e. mean / sd or possibly the mode)
A useful intuition of the beta distribtion can be found here
and a useful website here
scaling
We can scale the beta by how aversive participants find the shock. i.e. it might update their learning as if there was .5 a shock or 1.5 of a shock depending on their own sensitivity to the aversiveness / punishment.
alpha
generalisation
We can do this with a single beta distribution for each phase (collapsing over the two stimuli). This would be akin to a per phase generalisation parameter in that it will be smaller if they tend to choose the same expectancy for both stimuli and larger if they tend to choose very differently for both stimuli.
However, because these variables are not really equivalent (i.e the reinforcement rate is different for both, and we use this in the model)
So instead we can create a paramater which is the value of cs- weighted by some value of the cs+. How much each individual weights by the Cs+ can be freely estimated by the model and can be the generalisation parameter.
So this would be vminus = vminus + (w)vplus (where the w parameter is the freely estimated parameter per person)
per stimulus We probably want to model cs+ and cs- separately too - so have a beta distribution characterised by sufficient parameters for each.
per trial
All of the above can then also be done with updating per trial.
leaky beta
we also need a model that incorporates ‘leak’. i.e. learning leak - likely that participants will update more based on more recent trials and learn less from the more distant trials as time progresses. See Toby’s paper for more.
uncertainty
We should consider incorportating a parameter that maps to participant uncertainty about outcomes.
anxiety
Might be worth incorporating this as a model paramater / feature. Read this for more.
Hypotheses About the Relationship of Cognition With Psychopathology Should be Tested by Embedding Them Into Empirical Priors (Moutoussist et al., 2018)
Log likelihood notes
As we are using a beta distribution, we will calculate log likelihood based on the probability function for the distribution (i.e. where will the peak of the shape be) given the participants response at each trial. So will add the probability density function given each trial response trial by trial for each of the CS+ and - summed together.
Will obtain 1 log likelihood and then 1 per trial and add together to make sure that these are comparable.
the basic stan terminology for this is below:
beta_lpdf(rating[t,p]|shape1[t,p],shape2[t,p])
where beta_lpdf is the probability density given the rating made and each of the two beta distribution shape parameters that we estimate.
This is what we will use to compare models.
Terminology
V == ‘value’. Baasically a parameter that is about the salience of the stimulus at any given point.
alpha == ‘learning rate’. A parameter that describes how sensitive people are to updating their learning. So a fast learning rate means that learning on any given trial is weighted more based on the trials immediatly preceding than past ones, and a slow learning rate means that all past events influence learning more evenly. Alex’s tennis analogy is good here (Federer - stable player, can predict a win based on all matches; Murray - volatile player; his last match is best predictor of next match performance). beta == ‘confidence’. This is sort of an error term - how much variance in rating choice is there for each person/trial. Can be thought of as the variance, or beta^2 as the sd.
Can be confusing as we are using beta distributions (different thing) which has two sufficient parameters a + b).
Beta distribution visualisation
and how they change depending on whether you change the beta or alpha parameters.
Here are some simulations I can change and play with the illustrate the same sort of thing.
[1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[1] 0.00 0.05 0.10 0.15 0.20 0.25 0.30 0.35 0.40 0.45 0.50 0.55 0.60 0.65 0.70 0.75 0.80 0.85 0.90 0.95
[21] 1.00
[1] "stable beta, increasing alpha"





[1] "stable alpha, increasing beta"





Models to write / run
Will probably do all per trial. Will do an early sensitivity check to confirm this.
- Single beta, no scaling
- Single beta, no scaling per trial.
*** At this point, compare the two above. Ensure the per trial fits better, and if it does then do all below per trial***
- "" scaled
- Single beta Single alpha reinforcement learning model (estimate both the beta and the alpha i.e. learning rate)
- Single beta single alpha reinforcement learning with mean + sd for the beta estimate as a parameter
- Beta per stimulus
- Beta per stimulus + generalisation parameter (Vminus = vminus + wvplus)
- Leaky beta
- Leaky beta + uncertainty
- Leaky beta + uncertainty + anxiety
Justification of model components
Alpha Learning rate parameter. If high then will be very influenced by previous trial events, if low, then will be more standardly influenced by accumulating events.
- Single alpha per person
- Assumes that learning rate is a constant for each individual that might be scaled by other factors, such as certainty or sensitivity.
Betas Variance/certainty parameter
- Single beta per person
- Assumes that the general variance around ratings is the same regardless of stimulus. i.e. as much uncertainty for CS+ asn CS-
- Two beta’s per person
- Assumes that confidence / uncertainty might differ by stimulus. Presumably as a factor of reinforcement rate.
Preliminary
Compare a priori to data
Simulate different learning rates
only doing this ‘accurately’ for the acquisition CS+, as the simulations require probability. I am using contingency for this (0.75). If set for 0 for all other phases and stimuli then it looks as if the learning should be flat regardless of alpha. We expect in reality that this probability will vary between people and will be unlikely to be zero. So test 12 and 18 trials with a probability of 0.5 and 0.2 as well.
12 trials; probability = 0.75
[1] "Simulated learning rates. 12 trials; probability = 0.75 (CSp acq contingency) \n"











12 trials; probability = 0.5
[1] "Simulated learning rates. 12 trials; Probability = 0.5\n"











12 trials; probability = 0.2
[1] "Simulated learning rates. 12 trials; Probability = 0.2\n"











18 trials; probability = 0.5
[1] "Simulated learning rates. 18 trials; Probability = 0.5\n"











18 trials; probability = 0.2
[1] "Simulated learning rates. 18 trials; Probability = 0.2\n"











Plot subset of trajectories in flare
package ‘data.table’ was built under R version 3.5.2data.table 1.12.0 Latest news: r-datatable.com
Attaching package: ‘reshape2’
The following objects are masked from ‘package:data.table’:
dcast, melt
package ‘dplyr’ was built under R version 3.5.2
Attaching package: ‘dplyr’
The following objects are masked from ‘package:data.table’:
between, first, last
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union




Try RStan
See if the basic punishment only learning model for the CS+ and CS- works with the FLARe master data
Run the 8schools check
From the rstan github
This is to check that all is compiling and working and to give and idea of data format etc.
Set up procedure to create and sync models.
This directs to my local machine here /Users/kirstin/Dropbox/SGDP/FLARe/FLARe_MASTER/Projects/Hierachal_modelling/Scripts and is remotely linked to the github repository here.
Make sure the most up to date stan file is in the remote repo
Analyses
Function block
test function
A function for running minimal, medium or maximal tests of the stan data. This changes how many chains and iterations are run
testing <- function(x) {
if (x %in% c('min',"Min")) {
chain_iter<<-400
warm_up<<-100
chain_n<<-1
} else if ( x %in% c('med' ,'Med')) {
chain_iter<<-1000
warm_up<<-500
chain_n<<-1
} else if ( x %in% c('max','Max')) {
chain_iter<<-2000
warm_up<<-1000
chain_n<<-2
} else if ( x %in% c('full' ,'Full')) {
chain_iter<<-4000
warm_up<<-1000
chain_n<<-4
} else if ( x %in% c('skip' ,'Skip')) {
chain_iter<<-0
warm_up<<-0
chain_n<<-0
}
}
Model run, load or skip
A function for either running the model, loading in the data if it already exists and doesnt need redoing, or skipping block entirely.
x is testing command, skip or load commans y is stan script z is flare_data set to use.
Note that this needs to have scriptdir and datadir existing in the workplace
model_run <- function(x,y,z) {
if (x %in% c('skip',"Skip")) {
stop("skipping this model")
}
if (x %in% c('min',"med","max","Min","Med","Max","full","Full")) {
print("running model")
testing(x)
stanname = y
stanfile <- file.path(scriptdir, stanname)
flare_data <- z
# note that flare_data is set up elsewhere (see block below)
flare_fit <- stan(file = stanfile, data = flare_data, iter=chain_iter, chains = chain_n) #add working dir?
save_name <- gsub(".stan",".rds", stanname)
saveRDS(flare_fit, file=file.path(datadir,save_name))
print(traceplot(flare_fit,'lp__'))
# extract fit data
return(summary(flare_fit))
}
if (x %in% c('load',"Load")) {
print("Loading existing model fit data")
stanname = gsub(".stan",".rds", y)
fitfile <- readRDS(file=paste0(datadir,stanname))
print(traceplot(fitfile,'lp__'))
return(summary(fitfile))
}
}
out describe
Function for describing the mean etc of freely estimated parameters from STAN output
out_describe<- function(summary,n,all = NULL){
library(dplyr)
print(paste0(chain_iter, " iterations ", ' on ', chain_n,' chains.',sep=" "))
print(paste("Estimated",(dim(summary$summary)[1]-1) / nsub,"Free paramaters per person",sep=" "))
summary <- data.frame(summary$summary[(1:(dim(summary$summary)-1)[1]),])
table <- summary %>%
mutate(parameter = rep(1:(dim(summary)[1]/n),each = n )) %>%
group_by(parameter) %>%
summarize(mean = mean(mean,na.rm=T),
se_mean = mean(se_mean,na.rm=),
sd = mean(sd,na.rm=T),
Rhat = mean(Rhat,na.rm=T))
param_names <- row.names(summary)[(seq(1,dim(summary)[1],n))]
table$parameter <- param_names
if (is.null(all) & dim(table)[1] > 10) {
print("This table is very large. Returning only the top 6 entries unless you have set the 3rd function option to 'all'. ")
return(head(table))
} else {
return(table)
}
}
BIC
Canonincal BIC function from log likelihood courtesy of Alex Pike
## canonical BIC function (Alex Pikes)
bic<-function(trials,neg_log_like,nparam) {
if (sum(neg_log_like<0)>0){print('check this is negative log likelihood!!')}
2*neg_log_like+nparam*log(trials) #canonical
}
model plot
a function for plotting BIC barchart for different models contained in a dataset
## model compare plot function
plot_models <- function(dataset) {
dataset$BIC <- odp(as.numeric(dataset$BIC))
dataset <- as.data.frame(na.omit(dataset))
yminv <- min(dataset$BIC,na.rm=T) -5
ymaxv <- max(dataset$BIC,na.rm=T) +5
plot <- ggplot(dataset,aes(x=reorder(model,BIC),y=BIC)) +
geom_bar(stat="identity") +
coord_flip() +
labs(title = "Model comparison",
y="Bayesian Information Criterion (BIC)") +
scale_y_continuous(limits=c(yminv,ymaxv),oob=rescale_none)
show(plot)
}
ODP
the below is a function that will format your numbers to one decimal place using sprintf
odp <- function(x) {
as.numeric(sprintf("%2.2f",x))
}
Create datasets
notes
We need to rescale our dataset here to be between 0 and 1.
Importantly, because we are using the proportion of trials that are not reinforced as a known parameter for statistical reasons (we don’t want a proportion of .75 and 1, better to have .25 and 0), we have made our rescaled expectancy values as 1 - rescaled(x). This means that we will still be able to interpret the results in the expected way (i.e. higher rating is greater expectation of the outcome).
Expectancy data
load in the week 1 app and lab data for FLARe pilot, TRT and headphones studies. Make it long form.
Try with acquisition data first. This is formatted with no column names, with no missing data.
Derivethe n parameter for both files and check these match
set up trial number
# create the n trials variable for RStan
ntrials=12
stanname='punish_only.stan'
minus_name <- 'bayes_acq_minus.csv'
plus_name <- "bayes_acq_plus.csv"
stanfile <- file.path(scriptdir, stanname)
minusfile <- file.path(datadir,minus_name)
plusfile <- file.path(datadir,plus_name)
minus <- fread(minusfile,data.table=F)
plus <-fread(plusfile,data.table=F)
nacqm <- dim(minus)[1]
nacqp <- dim(plus)[1]
## check that these match and create nsub variable for RStan
if (nacqm == nacqp) {
print('subject number match')
nsub <- nacqm
print(paste('nsub set to',nsub,sep=" "))
} else {
print('WARNING: subject number does not match. Check master dataset')
}
[1] "subject number match"
[1] "nsub set to 335"
# check the file format is ok
minus[1:2,]
V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12
1 5 4 3 1 2 2 1 2 3 2 3 2
2 8 8 1 5 4 3 2 1 1 1 1 1
plus[1:2,]
V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12
1 5 6 7 4 7 7 6 7 2 8 7 8
2 1 9 9 5 8 8 9 9 9 8 9 8
The expectancy rating datasets look like they are formatted fine and ntrials and nsub variables should exist.
make rating data binary
for now to see if stan runs using bernoulli-logit function make binary resposnes from expectancy i.e. >=4.5 ==1, <= 4.5 ==0.
binarise <- function(x) {
ifelse(x >= 4.5,1,0)
}
minusb <- data.frame(apply(minus,2,function(x) binarise(x)))
plusb <- data.frame(apply(plus,2,function(x) binarise(x)))
Proportion screams data
This is a vector containing the absolute number of trials where no scream occurred for each stimulus. As there was a 75% reinforcement rate for the CS+ (9/12 trials), this is a vector of ’3’s. For the CS-, no trials were reinforced so is a vector of ’12’s
No_scream_p <- rep(3,nsub)
No_scream_m <- rep(12,nsub)
Scream per trial data
Create datasets for the acquisition CS- and extinction CS+ and CS- reflecting that no screams occurred at all. Then use the pattern id variable to create a dataset for the acquisition CS+ indicating when a scream occurred for each participant.
## Create the no scream daatsets for all
screamMinus <- matrix(0L,nrow=nsub, ncol=ntrials)
library(data.table)
## read in the screams for acquisition
screamPlus <- fread("/Users/kirstin/Dropbox/SGDP/FLARe/FLARe_MASTER/Projects/LatentGrowth/Datasets/bayes_screams_acq.csv",data.table=F)
#
# ### for the time being, simulate the NA data for the studies where I havent yet finished cleaning the screams.
#
# # make the first trial 1 for everyone, then add 8 additional random 1's per person. Do this in four random patterns to mimic the real data
#
# sc1 <- c(1,1,0,1,0,0,1,1,1,1,1)
# sc2 <- c(0,1,1,1,0,0,1,1,1,1,1)
# sc3 <- c(1,1,1,0,1,0,1,0,1,1,1)
# sc4 <- c(1,0,1,1,0,0,1,1,1,1,1)
#
#
# screamPlus[,1] <- ifelse(is.na(screamPlus[,1]),1,screamPlus[,1])
#
# # for (n in 1:dim(screamPlus)[1]) {
# # print(n)
# # screamPlus[n,2:12] <- sample(patts,1,replace=T)
# # }
#
# for (n in 1:dim(screamPlus)[1]) {
#
# a <- sample(c(1,4),1)
#
# if (is.na(screamPlus[n,2])){
# if (a == 1) {
# screamPlus[n,2:12] <- sc1
# } else if (a == 2) {
# screamPlus[n,2:12] <- sc2
# } else if (a == 3){
# screamPlus[n,2:12] <- sc3
# } else {
# screamPlus[n,2:12] <- sc4
# }
# }
# }
Create dataset for barplot comparing output
library(ggplot2)
mod_comp <- data.frame(model=NA,BIC=NA)
rescale data
rescale the 1-9 expectancy values to be on a 0-1 scale.
stan cannot deal with the extreme limit of the beta, so make the rescaled limits just above 0 and below one
Note that when a value had to be imputed as it was missing it will not be an integer. Thus the function needs to allow for ranges between values.
library(scales)
Attaching package: ‘scales’
The following object is masked from ‘package:purrr’:
discard
The following object is masked from ‘package:readr’:
col_factor
The following objects are masked from ‘package:psych’:
alpha, rescale
# rescale and flip so that we are effectively rating the expectation that they WILL NOT hear a scream to match stan
## rescaling such that the distribution spaces the numbers 1-9 evenly. the first interval upper bound would be 0.11, then 0.22 etc. this means that the mid point of each itnerval will be:
print("mid point of each evenly spaced interval representing values between 1-9")
[1] "mid point of each evenly spaced interval representing values between 1-9"
seq(0.5/9,1,1/9)
[1] 0.05555556 0.16666667 0.27777778 0.38888889 0.50000000 0.61111111 0.72222222 0.83333333 0.94444444
## thus 1 will be 1-0.055 etc.
## NOTE: might want to consider making this more flexible. enter in the numer of choice options as a variable - would be very easy. add to function library at later stage
scale_flare <- function(x){
vals <- seq(0.5/9,1,1/9)
for (val in 1:9){
if (x > val-1 & x <= val){
x <- 1 - vals[val]
}
}
return(x)
}
## initialise minus_scaled dataframe.
minus_scaled <- data.frame(matrix(ncol=dim(minus)[2],nrow = dim(minus)[1]))
## populate with rexcaled values
for (sub in 1:dim(minus)[1]){
for (col in 1:dim(minus)[2]){
minus_scaled[sub,col] <- scale_flare(minus[sub,col])
}
}
## ditto for plus
plus_scaled <- data.frame(matrix(ncol=dim(minus)[2],nrow = dim(minus)[1]))
for (sub in 1:dim(plus)[1]){
for (col in 1:dim(plus)[2]){
plus_scaled[sub,col] <- scale_flare(plus[sub,col])
}
}
## this is the number that will take from the midpoint to the top and bottom for the new boundaries (with ratings representing the midpoint)
cdf_scale <- 1/18
Set up stan
These use Alex Pikes RStan script with minor modification to make it punishment only to see if it runs. Testing that the approach works with the current data set up etc.
The settings for the script are below, including stan chain parameters and directory set up.
This loads the libraries and source files needed to run this script, and sets up RStan
Stan data
## Test data (Pilot + TRT + Validation) proportion no screams
#data
data_files<-list(ntrials=ntrials,nsub=nsub,nothingPlus = No_scream_p, nothingMinus=No_scream_m,ratingsPlus=plus_scaled,ratingsMinus=minus_scaled)
## Test data (Pilot + TRT + Validation) proportion screams, no log likelihood
flare_data_nolog <-list(ntrials=ntrials,nsub=nsub,screamPlus = t(screamPlus), screamMinus= t(screamMinus),ratingsPlus=t(plus_scaled),ratingsMinus=t(minus_scaled))
## Test data (Pilot + TRT + Validation) proportion screams, no log likelihood
flare_data<-list(ntrials=ntrials,nsub=nsub,screamPlus = t(screamPlus), screamMinus=t(screamMinus),ratingsPlus=t(plus_scaled),ratingsMinus=t(minus_scaled),cdf_scale=cdf_scale)
## Validation data (TEDS) scaled
#
# TEDS_data<-list(ntrials=ntrials,nsub=nsub,screamPlus = t(screamPlus), screamMinus= t(screamMinus),ratingsPlus=t(plus_scaled),ratingsMinus=t(minus_scaled))
Baseline models
Model 1: single beta no scaling
notes
Because we use the 1-rescaled expectancy data, no need to try and invert to reinforcement parameters here. As a result we need the stan model to simply be:
alphaPlus[p] = nothingPlus[p]/ntrials;
alphaMinus[p] = nothingMinus[p]/ntrials;
run Alex Pike’s stan script for non scaled beta model.
here we try to estimate the alpha parameter of the beta distribution per trial per person per stimulus. (i.e. you have two sufficient parameters for each beta dist, the alpha and beta. we want to estimate the alpha - ).
Eventually we will scale these by the actual ‘value’ of the scream for each person per trial.
Using data loaded in from preliminary tests above.
so this is a beta value per person (assuming the underlying process for the plus and minus are the same)
Model
#script
stanname='beta_noscaling.stan'
#data
data_files<-list(ntrials=ntrials,nsub=nsub,nothingPlus = No_scream_p, nothingMinus=No_scream_m,ratingsPlus=plus_scaled,ratingsMinus=minus_scaled)
flare_fit <- model_run('load','beta_noscaling.stan',data_files)
## get some basic output descriptions printed to screen
out_describe(flare_fit,nsub)
# extract fit data
summary_flare <- summary(flare_fit)
Model 2: single beta scaled
notes
Simple alteration of the first model. We estimate a scaling parameter per person over all trials and apply this to alpha component per participant.
run Alex Pike’s stan script for scaled beta model.
here we try to estimate the alpha parameter of the beta distribution per trial per person per stimulus. (i.e. you have two sufficient parameters for each beta dist, the alpha and beta. we want to estimate the alpha - ).
Eventually we will scale these by the actual ‘value’ of the scream for each person per trial.
Using data loaded in from preliminary tests above.
so this is a beta value per person (assuming the underlying process for the plus and minus are the same)
Model
flare_fit <- model_run('max',stanname,data_files)
[1] "running model"
starting worker pid=49421 on localhost:11817 at 12:36:45.564
starting worker pid=49431 on localhost:11817 at 12:36:45.790
SAMPLING FOR MODEL 'beta_scaling' NOW (CHAIN 1).
Chain 1:
Chain 1: Gradient evaluation took 0.001189 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 11.89 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1:
Chain 1:
Chain 1: Iteration: 1 / 2000 [ 0%] (Warmup)
SAMPLING FOR MODEL 'beta_scaling' NOW (CHAIN 2).
Chain 2:
Chain 2: Gradient evaluation took 0.002262 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 22.62 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2:
Chain 2:
Chain 2: Iteration: 1 / 2000 [ 0%] (Warmup)
Chain 2: Iteration: 200 / 2000 [ 10%] (Warmup)
Chain 1: Iteration: 200 / 2000 [ 10%] (Warmup)
Chain 2: Iteration: 400 / 2000 [ 20%] (Warmup)
Chain 1: Iteration: 400 / 2000 [ 20%] (Warmup)
Chain 2: Iteration: 600 / 2000 [ 30%] (Warmup)
Chain 1: Iteration: 600 / 2000 [ 30%] (Warmup)
Chain 2: Iteration: 800 / 2000 [ 40%] (Warmup)
Chain 1: Iteration: 800 / 2000 [ 40%] (Warmup)
Chain 2: Iteration: 1000 / 2000 [ 50%] (Warmup)
Chain 2: Iteration: 1001 / 2000 [ 50%] (Sampling)
Chain 1: Iteration: 1000 / 2000 [ 50%] (Warmup)
Chain 1: Iteration: 1001 / 2000 [ 50%] (Sampling)
Chain 1: Iteration: 1200 / 2000 [ 60%] (Sampling)
Chain 2: Iteration: 1200 / 2000 [ 60%] (Sampling)
Chain 1: Iteration: 1400 / 2000 [ 70%] (Sampling)
Chain 1: Iteration: 1600 / 2000 [ 80%] (Sampling)
Chain 2: Iteration: 1400 / 2000 [ 70%] (Sampling)
Chain 1: Iteration: 1800 / 2000 [ 90%] (Sampling)
Chain 1: Iteration: 2000 / 2000 [100%] (Sampling)
Chain 1:
Chain 1: Elapsed Time: 122.944 seconds (Warm-up)
Chain 1: 43.873 seconds (Sampling)
Chain 1: 166.817 seconds (Total)
Chain 1:
Chain 2: Iteration: 1600 / 2000 [ 80%] (Sampling)
Chain 2: Iteration: 1800 / 2000 [ 90%] (Sampling)
Chain 2: Iteration: 2000 / 2000 [100%] (Sampling)
Chain 2:
Chain 2: Elapsed Time: 117.623 seconds (Warm-up)
Chain 2: 83.1269 seconds (Sampling)
Chain 2: 200.749 seconds (Total)
Chain 2:
Warning message:
package ‘StanHeaders’ was built under R version 3.5.2
Warning message:
package ‘StanHeaders’ was built under R version 3.5.2

## get some basic output descriptions printed to screen
out_describe(flare_fit,nsub)
[1] "2000 iterations on 2 chains. "
[1] "Estimated 2 Free paramaters per person"
# extract fit data
summary_flare <- summary(flare_fit)
run Alex Pike’s stan script for scaled beta model.
here we try to estimate the alpha parameter of the beta distribution per trial per person per stimulus. (i.e. you have two sufficient parameters for each beta dist, the alpha and beta. we want to estimate the alpha - ).
Eventually we will scale these by the actual ‘value’ of the scream for each person per trial.
Using data loaded in from preliminary tests above.
so this is a beta value per person (assuming the underlying process for the plus and minus are the same)
#script
stanname='beta_withRL.stan'
flare_fit <- model_run('med',stanname,flare_data)
[1] "running model"
SAMPLING FOR MODEL 'beta_withRL' NOW (CHAIN 1).
Chain 1:
Chain 1: Gradient evaluation took 0.006291 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 62.91 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1:
Chain 1:
Chain 1: Iteration: 1 / 1000 [ 0%] (Warmup)
Chain 1: Iteration: 100 / 1000 [ 10%] (Warmup)
Chain 1: Iteration: 200 / 1000 [ 20%] (Warmup)
Chain 1: Iteration: 300 / 1000 [ 30%] (Warmup)
Chain 1: Iteration: 400 / 1000 [ 40%] (Warmup)
Chain 1: Iteration: 500 / 1000 [ 50%] (Warmup)
Chain 1: Iteration: 501 / 1000 [ 50%] (Sampling)
Chain 1: Iteration: 600 / 1000 [ 60%] (Sampling)
Chain 1: Iteration: 700 / 1000 [ 70%] (Sampling)
Chain 1: Iteration: 800 / 1000 [ 80%] (Sampling)
Chain 1: Iteration: 900 / 1000 [ 90%] (Sampling)
Chain 1: Iteration: 1000 / 1000 [100%] (Sampling)
Chain 1:
Chain 1: Elapsed Time: 92.0107 seconds (Warm-up)
Chain 1: 62.1928 seconds (Sampling)
Chain 1: 154.204 seconds (Total)
Chain 1:

## get some basic output descriptions printed to screen
out_describe(flare_fit,nsub)
[1] "1000 iterations on 1 chains. "
[1] "Estimated 2 Free paramaters per person"
# extract fit data
summary_flare <- summary(flare_fit)
Model 3: RL, mean defined, single beta
notes
this model includes an alpha learning paramater per person estimating their learning rate and updating based on it. This model needs a dataset that indicates whether a scream occurred for each trial instead of the proportion of times no scream occurred.
Mean to define shape
this model includes an alpha learning paramater per person estimating their learning rate and updating based on it. This model needs a dataset that indicates whether a scream occurred for each trial instead of the proportion of times no scream occurred.
Alex used this stack post to help solve the shape parameters using mean and sd where we assume that v serves as the mean and beta as the sd.
the equations work out to this:
for shape 1:
\[\alpha = \left(\frac{1-\mu}{\sigma^2} - \frac{1}{\mu}\right)\mu^2\]
for shape 2:
\[\beta=\alpha \left(\frac{1}{\mu}-1\right)\] ### Model
this way of defining the mean does not work or even run, so skipping it.
#script
stanname='beta_meansd_RL.stan'
flare_fit <- model_run('skip',stanname,flare_data_nolog)
## get some basic output descriptions printed to screen
out_describe(flare_fit,nsub)
# extract fit data
summary_flare <- summary(flare_fit)
On 500 iterations (i.e. test) the variance in alpha is good, but the traceplot is terrible. Model coverges very poorly. We also have to constrain the beta to be betwqeen 0 and 0.0001. Not sure why this is.
when running for 2000 iterations (1000 warmup)…
This results in the following warning;
There were 2644 divergent transitions after warmup. Increasing adapt_delta above 0.8 may help. See http://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmupThere were 4 transitions after warmup that exceeded the maximum treedepth. Increase max_treedepth above 10. See http://mc-stan.org/misc/warnings.html#maximum-treedepth-exceededThere were 4 chains where the estimated Bayesian Fraction of Missing Information was low. See http://mc-stan.org/misc/warnings.html#bfmi-lowExamine the pairs() plot to diagnose sampling problems
Mean definition 2
The above mean definition does not map the data well (terrible traceplot!). I found this from the MRC BSU and have tried defining the beta parameters assuming V == mean in a slighty different way:
for paramater a:
\[\alpha = \mu\beta/(1-\mu)\]
for parameter b:
\[\beta = \mu(1-\mu)^2/\sigma+\mu-1\]
Model
Still using a single beta here.
skipping as it also does not run
#script
stanname='beta_meansd_RL_2.stan'
flare_fit <- model_run('skip',stanname,flare_data_nolog)
## get some basic output descriptions printed to screen
out_describe(flare_fit,nsub)
# extract fit data
summary_flare <- summary(flare_fit)
Mean definition 3
noted that the shape parameters have slight variations in definition according to discussion here. Updated the script slightly to reflect this based on the reply from ocram.
the first sd term in shape a is changed to variance, so it changes from:
\[\alpha = \left(\frac{1-\mu}{\sigma^2} - \frac{1}{\mu}\right)\mu^2\]
to
\[\alpha = \left(\frac{1-\mu}{\sigma} - \frac{1}{\mu}\right)\mu^2\]
Changes the shape 2 parameter definition from:
\[\beta=\alpha \left(\frac{1}{\mu}-1\right)\]
to
\[\beta = \left(\frac{1-\mu}{\sigma} - \frac{1}{\mu}\right)\mu\left(1-\mu\right)\]
Because this works best, will add loglikelihhod calculation here. Basing this on the probability density function for the beta distribution given the participants actual ratings and sufficient parameters of the distribution per trial.
loglik[p] = loglik[p] + beta_lpdf(ratingsPlus[t,p]|shape1_Plus[t,p],shape2_Plus[t,p]) + beta_lpdf(ratingsMinus[t,p]|shape1_Minus[t,p],shape2_Minus[t,p])
Model
Skip as this definition also does not work or run
#script
stanname='beta_meansd_RL_3.stan'
flare_fit <- model_run('skip',stanname,flare_data_nolog)
## get some basic output descriptions printed to screen
out_describe(flare_fit,nsub)
# extract fit data
summary_flare <- summary(flare_fit)
This model is substnatially better than either of the other two. Traceplot suggests that the iterations converge as we would like. However, we still need to massively constrain the beta (i.e. confidence / uncertainty) estimates for it to run, otherwise the starting values drop below zero.
Mean definition 4
Here I try to define the parameter using simplified mean and precision estimates as per this tutorial. See in particular the parameter estimation on the cubs data.
This results in a relatively simplified parameter estimation compared to model 3.
\[\alpha = \mu * ((\mu * (1-\mu)) / \sigma - 1)\]
where mu is the mean (or value) and sigma is the variance / uncertainty parameter we currently call beta.
and the b (or shape 2) parameter for the distribution is:
\[\beta = (1- \mu) * ((\mu * (1-\mu)) / \sigma - 1)\]
Model
#script
stanname='beta_meansd_RL_4.stan'
flare_fit <- model_run('full',stanname,flare_data)
[1] "running model"
starting worker pid=49897 on localhost:11817 at 12:44:22.799
starting worker pid=49907 on localhost:11817 at 12:44:23.045
starting worker pid=49917 on localhost:11817 at 12:44:23.284
starting worker pid=49927 on localhost:11817 at 12:44:23.510
SAMPLING FOR MODEL 'beta_meansd_RL_4' NOW (CHAIN 1).
SAMPLING FOR MODEL 'beta_meansd_RL_4' NOW (CHAIN 2).
SAMPLING FOR MODEL 'beta_meansd_RL_4' NOW (CHAIN 3).
SAMPLING FOR MODEL 'beta_meansd_RL_4' NOW (CHAIN 4).
Chain 1:
Chain 1: Gradient evaluation took 0.015671 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 156.71 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1:
Chain 1:
Chain 1: Iteration: 1 / 4000 [ 0%] (Warmup)
Chain 2:
Chain 2: Gradient evaluation took 0.014001 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 140.01 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2:
Chain 2:
Chain 2: Iteration: 1 / 4000 [ 0%] (Warmup)
Chain 3:
Chain 3: Gradient evaluation took 0.013264 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 132.64 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3:
Chain 3:
Chain 4:
Chain 4: Gradient evaluation took 0.015048 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 150.48 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4:
Chain 4:
Chain 3: Iteration: 1 / 4000 [ 0%] (Warmup)
Chain 4: Iteration: 1 / 4000 [ 0%] (Warmup)
Chain 3: Iteration: 400 / 4000 [ 10%] (Warmup)
Chain 4: Iteration: 400 / 4000 [ 10%] (Warmup)
Chain 1: Iteration: 400 / 4000 [ 10%] (Warmup)
Chain 2: Iteration: 400 / 4000 [ 10%] (Warmup)
Chain 4: Iteration: 800 / 4000 [ 20%] (Warmup)
Chain 2: Iteration: 800 / 4000 [ 20%] (Warmup)
Chain 3: Iteration: 800 / 4000 [ 20%] (Warmup)
Chain 1: Iteration: 800 / 4000 [ 20%] (Warmup)
Create BIC from log likelihood
## extract log likelihood
flare_loglike <- extract_log_lik(flare_fit, parameter_name = "loglik", merge_chains = TRUE)
#calculate BIC
FLARe_bic<-bic(ntrials,-colMeans(flare_loglike_best),2) #number of parameters in that model e.g. 4)
## mean BIC as model comparisons tool:
print("Mean Bayesian information criterion for model")
mean(FLARe_bic)
Add to bar plot
mod_comp <- rbind(mod_comp,c("Means 1 beta",as.numeric(mean(FLARe_bic))))
mod_comp$BIC <- odp(as.numeric(mod_comp$BIC))
mod_comp <- as.data.frame(na.omit(mod_comp))
## plot function - create plot
plot_models(mod_comp)
Model 4: RL, mode defined, single beta
notes
Used this post to guide this. particularly:
For a beta distribution with shape parameters a and b, the mode is (a-1)/(a+b-2). Suppose we have a desired mode, and we want to determine the corresponding shape parameters. Here’s the solution. First, we express the “certainty” of the estimate in terms of the equivalent prior sample size, k=a+b, with k≥2. The certainty must be at least 2 because it essentially assumes that the prior contains at least one “head” and one “tail,” which is to say that we know each outcome is at least possible. Then a little algebra reveals: a = mode * (k-2) + 1 b = (1-mode) * (k-2) + 1
shape 1 as mode with v and beta as beta shape parameters
For this version we try and estimate the ‘mode’ to be shape 1. KIRSTIN:: explain here
Model
doesnt work, so skip this first attempt
#script
stanname='beta_mode_RL.stan'
flare_fit <- model_run('skip',stanname,flare_data_nolog)
## get some basic output descriptions printed to screen
out_describe(flare_fit,nsub)
# extract fit data
summary_flare <- summary(flare_fit)
v as mode
For this version we assume that V is the mode (above we assumed it serves as the mean) and beta is the certainty aspect (i.e. k)
What this does is basically treat the expected rating (value) as the a parameter for the distribution (scaled by their certainity - beta) and 1-that value as the b parameter (again, scaled by the uncertainty).
so you have a ratio of their selected value per trial (mode across iterations?) to how far from the highest possible choice they are.
Model
#script
stanname='beta_mode_RL_2.stan'
flare_fit <- model_run('med',stanname,flare_data)
## get some basic output descriptions printed to screen
out_describe(flare_fit,nsub)
# extract fit data
summary_flare <- summary(flare_fit)
This works, but there is not a lot of variance in the alpha parameter when described by mode mean 0.49; sd = 0.06. Compared to defined by mean where mean is 0.54 and sd is 0.26.
However there is a lot of variation in the beta parameter (mean -7.21, sd = 134.74)
Create BIC from log likelihood
## extract log likelihood
flare_loglike <- extract_log_lik(flare_fit, parameter_name = "loglik", merge_chains = TRUE)
#calculate BIC
FLARe_bic<-bic(ntrials,-colMeans(flare_loglike),2) #number of parameters in that model e.g. 4)
## mean BIC as model comparisons tool:
print("Mean Bayesian information criterion for model")
mean(FLARe_bic)
Add to bar plot
mod_comp <- rbind(mod_comp,c("Mode 1 beta",as.numeric(mean(FLARe_bic))))
mod_comp$BIC <- odp(as.numeric(mod_comp$BIC))
mod_comp <- as.data.frame(na.omit(mod_comp))
## plot function - create plot
plot_models(mod_comp)
Model 5: RL mean defined,two beta
Model
RL model adding a beta per stimulus to Alex’s model
#script
stanname='beta_meansd_2beta_RL.stan'
flare_fit <- model_run('full',stanname,flare_data)
## get some basic output descriptions printed to screen
out_describe(flare_fit,nsub)
# extract fit data
summary_flare <- summary(flare_fit)
Create BIC from log likelihood
## extract log likelihood
flare_loglike_m2 <- extract_log_lik(flare_fit_m2, parameter_name = "loglik", merge_chains = TRUE)
#calculate BIC
FLARe_bic_m2 <- bic(ntrials,-colMeans(flare_loglike_m2),3) #number of parameters in that model e.g. 4)
# mean for all participants
mean(FLARe_bic_m2)
Add to bar plot
mod_comp <- rbind(mod_comp,c("Means 2 beta",mean(FLARe_bic_m2)))
mod_comp$BIC <- odp(as.numeric(mod_comp$BIC))
mod_comp <- as.data.frame(na.omit(mod_comp))
## plot function - create plot
plot_models(mod_comp)
Model 6: RL mode defined,two beta
Model
RL model adding a beta per stimuli to model defining the beta shape using the mode instead of the mean. This definitely makes more sense as we assume that they will have different levels of uncertainty about each.
#script
stanname='beta_mode_2beta_RL_2.stan'
flare_fit <- model_run('full',stanname,flare_data_nolog)
## get some basic output descriptions printed to screen
out_describe(flare_fit,nsub)
# extract fit data
summary_flare <- summary(flare_fit)
The alpha parameter variance is normal (mean 0.4 and sd 0.12). Beta is much more bounded now though (combined across both stimuli mean 0.79, sd=1.6) over 4000 iterations on 4 chains.
Create BIC from log likelihood
## extract log likelihood
flare_loglike <- extract_log_lik(flare_fit, parameter_name = "loglik", merge_chains = TRUE)
#calculate BIC
FLARe_bic<-bic(ntrials,-colMeans(flare_loglike),2) #number of parameters in that model e.g. 4)
## mean BIC as model comparisons tool:
print("Mean Bayesian information criterion for model")
mean(FLARe_bic)
Add to bar plot
mod_comp <- rbind(na.omit(mod_comp),c("Mode 2 beta",mean(FLARe_bic)))
mod_comp$BIC <- odp(as.numeric(mod_comp$BIC))
mod_comp <- as.data.frame(na.omit(mod_comp))
## plot function - create plot
plot_models(mod_comp)
Model 7: RL mean defined, no beta
Model
The beta doesnt work as well for the CS+ stimulus, need to check if this parameter adds anything to the model - drop it from our best mean model and see how this changes the fit.
this takes for ever to run and the logliklihood fails. So no idea if it is good yet - come back to this. skipped for now
#script
stanname='beta_meansd_RL_NoBeta.stan'
flare_fit <- model_run('skip',stanname,flare_data_nolog)
## get some basic output descriptions printed to screen
out_describe(flare_fit,nsub)
# extract fit data
summary_flare <- summary(flare_fit)
Create BIC from log likelihood
#
# ## extract log likelihood
#
# flare_loglike <- extract_log_lik(flare_fit, parameter_name = "loglik", merge_chains = TRUE)
#
# #calculate BIC
#
# FLARe_bic<-bic(ntrials,-colMeans(flare_loglike),2) #number of parameters in that model e.g. 4)
#
# ## mean BIC as model comparisons tool:
#
# print("Mean Bayesian information criterion for model")
# mean(FLARe_bic)
Add to bar plot
#
# mod_comp <- rbind(na.omit(mod_comp),c("Mean no beta",mean(FLARe_bic)))
#
# #
# mod_comp$BIC <- odp(as.numeric(mod_comp$BIC))
#
# mod_comp <- as.data.frame(na.omit(mod_comp))
#
## plot function - create plot
# plot_models(mod_comp)
Generate and recover
Here I test whether the model is working well by seeing if I can use the parameters we’ve estimated to try and generate our existing rating data and then recover similar parameters again.
I will do this for the best fitting model (mean defined beta distribution with a variance estimate per person for eahc stimulus) This is the model where we treat the iterarted ratings as if they are ‘expected’ values and use this as shape 1 parameter for our beta distribution at each trial. We have allowed a beta (or uncertainty) parameter per stimulus.
A good model will have a) a good correlation between real data and the data generated and b) a good correlation between the parameter estimates from the real and generated data.
We basically want to replicate our stan script, but inatead of estimating paratmers, we want to assume that we know what the parameters are (i.e. use the alpha and beta’s we have estimated previously).
update: turns out single beta is the best fitting model when I correct my BIC function to include the negative log likelihood. So will also generate and recover for this model and use this as the comparator.
Mean 1 beta
Generate
Make alpha / beta datasets p/p
Use the summary of the stan model to extract the different parameters we want to try to use to recreate our data.
params <- summary(flare_fit_best)
alpha_est <- data.frame(params$summary[1:nsub,1])
beta <- data.frame(params$summary[(nsub+1):(nsub*2),1])
names(beta) <- "beta"
Initialise empty datasets to hold the predicted ratings
rating_est_plus <- data.frame(matrix(ncol=ntrials,nrow=nsub))
rating_est_minus <- data.frame(matrix(ncol=ntrials,nrow=nsub))
# beta shape parameters
shape1p <- data.frame(matrix(ncol=ntrials,nrow=nsub))
shape1m <- data.frame(matrix(ncol=ntrials,nrow=nsub))
shape2p <- data.frame(matrix(ncol=ntrials,nrow=nsub))
shape2m <- data.frame(matrix(ncol=ntrials,nrow=nsub))
# V parameters (initialised at 0.5)
vp <- data.frame(matrix(ncol=ntrials,nrow=nsub))
vm <- data.frame(matrix(ncol=ntrials,nrow=nsub))
vp[1] <- 0.5
vm[1] <- 0.5
# prediction error
dp <- data.frame(matrix(ncol=(ntrials-1),nrow=nsub))
dm <- data.frame(matrix(ncol=(ntrials-1),nrow=nsub))
Simulate ratings
Use our extracted parameters in place of estimating the same. Use the stan syntax
Populate our vplus and delta frames
use the alpha parameters we’ve extracted (alpha_est) d == delta (precdiction error) v == value (i.e. value for each stimulus)
for (p in 1:nsub){
for (t in 1:(ntrials-1)){
dp[p,t] <- screamPlus[p,t]-vp[p,t]
dm[p,t] <- screamMinus[p,t]-vm[p,t]
vp[p,t+1] <- vp[p,t]+alpha_est[p,1]*dp[p,t]
vm[p,t+1]<- vm[p,t]+alpha_est[p,1]*dm[p,t]
}
}
for (t in 1:ntrials){
shape1_Plus[t,p] = VPlus[t,p] * ((VPlus[t,p] * (1-VPlus[t,p])) / beta[p,1]);
shape1_Minus[t,p] = VMinus[t,p] * ((VMinus[t,p] * (1-VMinus[t,p])) / beta[p,2]);
shape2_Plus[t,p] = (1-VPlus[t,p]) * ((VPlus[t,p] * (1-VPlus[t,p])) / beta[p,1]);
shape2_Minus[t,p] = (1-VMinus[t,p]) * ((VMinus[t,p] * (1-VMinus[t,p])) / beta[p,2]);
ratingsPlus[t,p] ~ beta(shape1_Plus[t,p],shape2_Plus[t,p]);
ratingsMinus[t,p] ~ beta(shape1_Minus[t,p],shape2_Minus[t,p]);
}
} }
populate beta parameter shape frames
Use the new v frames and beta parameters.
Shape 1 and 2 are sufficient parameters for the beta distribution
for (p in 1:nsub){
for (t in 1:ntrials){
shape1p[p,t] = vp[p,t] * ((vp[p,t] * (1-vp[p,t])) / beta[p,1])
shape1m[p,t] = vm[p,t] * ((vm[p,t] * (1-vm[p,t])) / beta[p,1])
shape2p[p,t] = (1-vp[p,t]) * ((vp[p,t] * (1-vp[p,t])) / beta[p,1])
shape2m[p,t] = (1-vm[p,t]) * ((vm[p,t] * (1-vm[p,t])) / beta[p,1])
}
}
Estimate ratings
trying to use pbeta here (derives the distribution function givemn a set of probabilities)
For now, setting probabilities between 0 and 1 and taking the average…
for (p in 1:nsub){
for (t in 1:ntrials){
rating_est_plus[p,t] <- mean(rbeta(1000,shape1p[p,t],shape2p[p,t]))
rating_est_minus[p,t] <- mean(rbeta(1000,shape1m[p,t],shape2m[p,t]))
}
}
Rescale simulated ratings
You could argue that these should match the discrete scale nature of the original ratings. We effectively undid this in our script. The following will enable this.
HOWEVER: we are redcucing variance massively this way, so think it might be better to leave the recovered ratings unscales….
So - the following discrete values exist in our rescaled ratings:
table(plus_scaled$X1)
Will make it that anything that falls 0.05555556 above or below one of these values is set to this median point. Note that this is our cdf_scale factor that we used in the script to capture the full area under the curve for each segment of the distribution represented by the discrete ratings of 1-9.
Write the function to rescale
scale_simulated <- function(x){
scaled_list <- array(unique(plus_scaled$X1))
for (val in scaled_list[1:length(scaled_list)]){
if (x > val-cdf_scale & x < val+cdf_scale){
x <- val
}
}
return(x)
}
apply it to the simulated rating frames.
(unhash to run this)
## initialise dataframes
#
# est_plus_scaled <- data.frame(matrix(ncol=dim(rating_est_plus)[2],nrow = dim(rating_est_plus)[1]))
# est_minus_scaled <- data.frame(matrix(ncol=dim(rating_est_minus)[2],nrow = dim(rating_est_minus)[1]))
#
# ## populate with rescaled values
#
# for (sub in 1:dim(rating_est_plus)[1]){
# for (col in 1:dim(rating_est_plus)[2]){
#
# est_plus_scaled[sub,col] <- scale_simulated(rating_est_plus[sub,col])
# }
# }
#
# for (sub in 1:dim(rating_est_minus)[1]){
# for (col in 1:dim(rating_est_minus)[2]){
#
# est_minus_scaled[sub,col] <- scale_simulated(rating_est_minus[sub,col])
# }
# }
Correlate actual ratings with simulated ratings
use the simulated ratings per person that we have derived using our parameters and see how well they align with the real ratings…
Only showing the diaganols from corr.test package here to get the important t1 x t1 etc values.
this will be using either rating_est files (rating_est_plus;rating_est_minus) or the est_scaled files (est_minus_scaled; est_plus_scaled) depending on whether we opt to return scaling or no
print("real ratings with estimated ratings: CS MINUS")
diag(corr.test(rating_est_minus,minus_scaled)$r)
print("real ratings with estimated ratings: CS MINUS (average for all trials)")
cor(rowMeans(rating_est_minus),rowMeans(minus_scaled))
print("real ratings with estimated ratings: CS PLUS")
diag(corr.test(rating_est_plus,plus_scaled)$r)
print("real ratings with estimated ratings: CS PLUS (average for all trials)")
cor(rowMeans(rating_est_plus),rowMeans(plus_scaled))
Recover
Here we are seeing if we can recover the same estimates using the simulated ratings. Basically run stan but using the estimated ratings instead of the real ones. See if we get the same alpha / beta parameters.
We might decide to use the rescaled estimates here to be more comparable…
run stan model
RL model adding a beta per stimulus to Alex’s model
#script
stanname='beta_meansd_RL_4.stan'
# data
flare_data_rec <-list(ntrials=ntrials,nsub=nsub,screamPlus = t(screamPlus), screamMinus= t(screamMinus),ratingsPlus=t(rating_est_plus),ratingsMinus=t(rating_est_minus),cdf_scale=cdf_scale)
flare_fit_rec <- model_run('full',stanname,flare_data_rec)
## get some basic output descriptions printed to screen
out_describe(flare_fit_rec,nsub)
Make alpha / beta datasets p/p
Use the summary of the stan model to extract the different parameters we want to try to use to recreate our data.
params_rec <- summary(flare_fit_rec)
alpha_est_rec <- data.frame(params_rec$summary[1:nsub,1])
beta_rec <- data.frame(params_rec$summary[(nsub+1):(nsub*2)])
names(beta_rec) <- "beta_rec"
Correlate actual ratings with simulated ratings
use the simulated ratings per person that we have derived using our parameters and see how well they align with the real ratings…
Only showing the diaganols from corr.test package here to get the important t1 x t1 etc values.
print("original with recovered: ALPHA")
diag(corr.test(alpha_est_rec,alpha_est)$r)
print("original with recovered: BETA")
diag(corr.test(beta_rec,beta)$r)
Mean 2 beta
Generate
Make alpha / beta datasets p/p
Use the summary of the stan model to extract the different parameters we want to try to use to recreate our data.
params <- summary(flare_fit_m2)
alpha_est <- data.frame(params$summary[1:nsub,1])
beta_plus <- data.frame(matrix(ncol = 1,nrow=nsub))
beta_minus <- data.frame(matrix(ncol = 1,nrow=nsub))
names(beta_plus) <- "beta_plus"
names(beta_minus) <- "beta_minus"
subp = 0
subm = 0
for ( i in 343:1026){
if (i%%2 == 1){
subp= subp+1
beta_plus[subp,1] <- params$summary[i,1]
} else if (i%%2 == 0) {
subm= subm+1
beta_minus[subm,1] <- params$summary[i,1]
}
}
Initialise empty datasets to hold the predicted ratings
rating_est_plus <- data.frame(matrix(ncol=ntrials,nrow=nsub))
rating_est_minus <- data.frame(matrix(ncol=ntrials,nrow=nsub))
# beta shape parameters
shape1p <- data.frame(matrix(ncol=ntrials,nrow=nsub))
shape1m <- data.frame(matrix(ncol=ntrials,nrow=nsub))
shape2p <- data.frame(matrix(ncol=ntrials,nrow=nsub))
shape2m <- data.frame(matrix(ncol=ntrials,nrow=nsub))
# V parameters (initialised at 0.5)
vp <- data.frame(matrix(ncol=ntrials,nrow=nsub))
vm <- data.frame(matrix(ncol=ntrials,nrow=nsub))
vp[1] <- 0.5
vm[1] <- 0.5
# prediction error
dp <- data.frame(matrix(ncol=(ntrials-1),nrow=nsub))
dm <- data.frame(matrix(ncol=(ntrials-1),nrow=nsub))
Simulate ratings
Use our extracted parameters in place of estimating the same. Use the stan syntax
Populate our vplus and delta frames
use the alpha parameters we’ve extracted (alpha_est) d == delta (precdiction error) v == value (i.e. value for each stimulus)
for (p in 1:nsub){
for (t in 1:(ntrials-1)){
dp[p,t] <- screamPlus[p,t]-vp[p,t]
dm[p,t] <- screamMinus[p,t]-vm[p,t]
vp[p,t+1] <- vp[p,t]+alpha_est[p,1]*dp[p,t]
vm[p,t+1]<- vm[p,t]+alpha_est[p,1]*dm[p,t]
}
}
for (t in 1:ntrials){
shape1_Plus[t,p] = VPlus[t,p] * ((VPlus[t,p] * (1-VPlus[t,p])) / beta[p,1]);
shape1_Minus[t,p] = VMinus[t,p] * ((VMinus[t,p] * (1-VMinus[t,p])) / beta[p,2]);
shape2_Plus[t,p] = (1-VPlus[t,p]) * ((VPlus[t,p] * (1-VPlus[t,p])) / beta[p,1]);
shape2_Minus[t,p] = (1-VMinus[t,p]) * ((VMinus[t,p] * (1-VMinus[t,p])) / beta[p,2]);
ratingsPlus[t,p] ~ beta(shape1_Plus[t,p],shape2_Plus[t,p]);
ratingsMinus[t,p] ~ beta(shape1_Minus[t,p],shape2_Minus[t,p]);
}
} }
populate beta parameter shape frames
Use the new v frames and beta parameters.
Shape 1 and 2 are sufficient parameters for the beta distribution
for (p in 1:nsub){
for (t in 1:ntrials){
shape1p[p,t] = vp[p,t] * ((vp[p,t] * (1-vp[p,t])) / beta_plus[p,1])
shape1m[p,t] = vm[p,t] * ((vm[p,t] * (1-vm[p,t])) / beta_minus[p,1])
shape2p[p,t] = (1-vp[p,t]) * ((vp[p,t] * (1-vp[p,t])) / beta_plus[p,1])
shape2m[p,t] = (1-vm[p,t]) * ((vm[p,t] * (1-vm[p,t])) / beta_minus[p,1])
}
}
Estimate ratings
trying to use pbeta here (derives the distribution function givemn a set of probabilities)
For now, setting probabilities between 0 and 1 and taking the average…
for (p in 1:nsub){
for (t in 1:ntrials){
rating_est_plus[p,t] <- mean(rbeta(1000,shape1p[p,t],shape2p[p,t]))
rating_est_minus[p,t] <- mean(rbeta(1000,shape1m[p,t],shape2m[p,t]))
}
}
Correlate actual ratings with simulated ratings
use the simulated ratings per person that we have derived using our parameters and see how well they align with the real ratings…
Only showing the diaganols from corr.test package here to get the important t1 x t1 etc values.
print("real ratings with estimated ratings: CS MINUS")
diag(corr.test(rating_est_minus,minus_scaled)$r)
print("real ratings with estimated ratings: CS MINUS (average for all trials)")
cor(rowMeans(rating_est_minus),rowMeans(minus_scaled))
print("real ratings with estimated ratings: CS PLUS")
diag(corr.test(rating_est_plus,plus_scaled)$r)
print("real ratings with estimated ratings: CS PLUS (average for all trials)")
cor(rowMeans(rating_est_plus),rowMeans(plus_scaled))
Recover
Here we are seeing if we can recover the same estimates using the simulated ratings. Basically run stan but using the estimated ratings instead of the real ones. See if we get the same alpha / beta parameters.
rescale the estimated ratings
rescale the 1-9 expectancy values to be on a 0-1 scale.
stan cannot deal with the extreme limit of the beta, so make the rescaled limits just above 0 and below one
Note that when a value had to be imputed as it was missing it will not be an integer. Thus the function needs to allow for ranges between values.
#
# minus_scaled_est <- data.frame(matrix(ncol=dim(rating_est_minus)[2],nrow = dim(rating_est_minus)[1]))
#
# ## populate with rexcaled values
#
# for (sub in 1:dim(rating_est_minus)[1]){
# for (col in 1:dim(rating_est_minus)[2]){
#
# minus_scaled_est[sub,col] <- scale_flare(rating_est_minus[sub,col])
# }
# }
#
# ## ditto for plus
#
# plus_scaled_est <- data.frame(matrix(ncol=dim(rating_est_plus)[2],nrow = dim(rating_est_plus)[1]))
#
# ## populate with rexcaled values
#
# for (sub in 1:dim(rating_est_plus)[1]){
# for (col in 1:dim(rating_est_plus)[2]){
#
# plus_scaled_est[sub,col] <- scale_flare(rating_est_plus[sub,col])
# }
# }
#
run stan model
RL model adding a beta per stimulus to Alex’s model
#script
stanname='beta_meansd_2beta_RL.stan'
# data
flare_data_rec <-list(ntrials=ntrials,nsub=nsub,screamPlus = t(screamPlus), screamMinus= t(screamMinus),ratingsPlus=t(rating_est_plus),ratingsMinus=t(rating_est_minus),cdf_scale=cdf_scale)
flare_fit_rec <- model_run('full',stanname,flare_data_rec)
## get some basic output descriptions printed to screen
out_describe(flare_fit_rec,nsub)
Make alpha / beta datasets p/p
Use the summary of the stan model to extract the different parameters we want to try to use to recreate our data.
params_rec <- summary(flare_fit_rec)
alpha_est_rec <- data.frame(params_rec$summary[1:nsub,1])
beta_plus_rec <- data.frame(matrix(ncol = 1,nrow=nsub))
beta_minus_rec <- data.frame(matrix(ncol = 1,nrow=nsub))
names(beta_plus_rec) <- "beta_plus"
names(beta_minus_rec) <- "beta_minus"
subp = 0
subm = 0
for ( i in 343:1026){
if (i%%2 == 1){
subp= subp+1
beta_plus_rec[subp,1] <- params_rec$summary[i,1]
} else if (i%%2 == 0) {
subm= subm+1
beta_minus_rec[subm,1] <- params_rec$summary[i,1]
}
}
Correlate actual ratings with simulated ratings
use the simulated ratings per person that we have derived using our parameters and see how well they align with the real ratings…
Only showing the diaganols from corr.test package here to get the important t1 x t1 etc values.
print("original with recovered: ALPHA")
diag(corr.test(alpha_est_rec,alpha_est)$r)
print("original with recovered: BETA PLUS")
diag(corr.test(beta_plus_rec,beta_plus)$r)
print("original with recovered: BETA MINUS")
diag(corr.test(beta_minus_rec,beta_minus)$r)
Expanding on the best base model
Potentially interesting parameters to add to best fit model
Model 8: Punishment sensitivity
How aversive they find the scream reinforcement. Modelling this on the loss aversion parameter in Charpentier et al (see the last page before references),
This will be a single parameter per person, and represents how much the scream influences their ratings.
Based on the paper, will try the following to model this in stan by including it in our value calcs for the CS+ and CS- respectively. we will do this by letting it influence how much their prediction error changes based on whether a scream occurred or not. The prediction error is later used to change the value rating per stimulus
\[d(stimulus,trial) = scream*\lambda-v(stimulus,trial-1)\]
where \[\lambda = sensitivity\\to\\screams\]
Model
#script
stanname='beta_mean1beta_PunSens.stan'
flare_fit <- model_run('full',stanname,flare_data)
## get some basic output descriptions printed to screen
out_describe(flare_fit,nsub)
# extract fit data
summary_flare <- summary(flare_fit)
Create BIC from log likelihood
## extract log likelihood
flare_loglike <- extract_log_lik(flare_fit, parameter_name = "loglik", merge_chains = TRUE)
#calculate BIC
FLARe_bic<-bic(ntrials,-colMeans(flare_loglike),2) #number of parameters in that model e.g. 4)
## mean BIC as model comparisons tool:
print("Mean Bayesian information criterion for model")
mean(FLARe_bic)
Add to bar plot
mod_comp <- rbind(na.omit(mod_comp),c("Punishment sensitivity",mean(FLARe_bic)))
mod_comp$BIC <- odp(as.numeric(mod_comp$BIC))
mod_comp <- as.data.frame(na.omit(mod_comp))
## plot function - create plot
plot_models(mod_comp)
Generate
Make alpha / beta datasets p/p
Use the summary of the stan model to extract the different parameters we want to try to use to recreate our data.
params <- summary(flare_fit)
alpha_est <- data.frame(params$summary[1:nsub,1])
beta <- data.frame(params$summary[(nsub+1):(nsub*2),1])
lambda <- data.frame(params$summary[(nsub*3+1):(nsub*4),1])
names(alpha_est) <- "alpha"
names(beta) <- "beta"
names(lambda) <- "lambda"
Initialise empty datasets to hold the predicted ratings
rating_est_plus <- data.frame(matrix(ncol=ntrials,nrow=nsub))
rating_est_minus <- data.frame(matrix(ncol=ntrials,nrow=nsub))
# beta shape parameters
shape1p <- data.frame(matrix(ncol=ntrials,nrow=nsub))
shape1m <- data.frame(matrix(ncol=ntrials,nrow=nsub))
shape2p <- data.frame(matrix(ncol=ntrials,nrow=nsub))
shape2m <- data.frame(matrix(ncol=ntrials,nrow=nsub))
# V parameters (initialised at random value between 0.5 - 0.05 and 0.5+0.05)
vp <- data.frame(matrix(ncol=ntrials,nrow=nsub))
vm <- data.frame(matrix(ncol=ntrials,nrow=nsub))
vp[1] <- rnorm(nsub,0.5,0.025)
vm[1] <- rnorm(nsub,0.5,0.025)
# prediction error
dp <- data.frame(matrix(ncol=(ntrials-1),nrow=nsub))
dm <- data.frame(matrix(ncol=(ntrials-1),nrow=nsub))
Simulate ratings
Use our extracted parameters in place of estimating the same. Use the stan syntax
Populate our vplus and delta frames
use the alpha parameters we’ve extracted (alpha_est) d == delta (precdiction error) v == value (i.e. value for each stimulus)
for (p in 1:nsub){
for (t in 1:(ntrials-1)){
dp[p,t] <- screamPlus[p,t]*lambda[p,]-vp[p,t]
dm[p,t] <- screamMinus[p,t]*lambda[p,]-vm[p,t]
vp[p,t+1] <- vp[p,t]+alpha_est[p,1]*dp[p,t]
vm[p,t+1]<- vm[p,t]+alpha_est[p,1]*dm[p,t]
}
}
for (t in 1:ntrials){
shape1_Plus[t,p] = VPlus[t,p] * ((VPlus[t,p] * (1-VPlus[t,p])) / beta[p,1]);
shape1_Minus[t,p] = VMinus[t,p] * ((VMinus[t,p] * (1-VMinus[t,p])) / beta[p,2]);
shape2_Plus[t,p] = (1-VPlus[t,p]) * ((VPlus[t,p] * (1-VPlus[t,p])) / beta[p,1]);
shape2_Minus[t,p] = (1-VMinus[t,p]) * ((VMinus[t,p] * (1-VMinus[t,p])) / beta[p,2]);
ratingsPlus[t,p] ~ beta(shape1_Plus[t,p],shape2_Plus[t,p]);
ratingsMinus[t,p] ~ beta(shape1_Minus[t,p],shape2_Minus[t,p]);
}
} }
populate beta parameter shape frames
Use the new v frames and beta parameters.
Shape 1 and 2 are sufficient parameters for the beta distribution
for (p in 1:nsub){
for (t in 1:ntrials){
shape1p[p,t] = vp[p,t] * ((vp[p,t] * (1-vp[p,t])) / beta[p,1])
shape1m[p,t] = vm[p,t] * ((vm[p,t] * (1-vm[p,t])) / beta[p,1])
shape2p[p,t] = (1-vp[p,t]) * ((vp[p,t] * (1-vp[p,t])) / beta[p,1])
shape2m[p,t] = (1-vm[p,t]) * ((vm[p,t] * (1-vm[p,t])) / beta[p,1])
}
}
Estimate ratings
trying to use pbeta here (derives the distribution function givemn a set of probabilities)
For now, setting probabilities between 0 and 1 and taking the average…
for (p in 1:nsub){
for (t in 1:ntrials){
rating_est_plus[p,t] <- mean(rbeta(1000,shape1p[p,t],shape2p[p,t]))
rating_est_minus[p,t] <- mean(rbeta(1000,shape1m[p,t],shape2m[p,t]))
}
}
Correlate actual ratings with simulated ratings
use the simulated ratings per person that we have derived using our parameters and see how well they align with the real ratings…
Only showing the diaganols from corr.test package here to get the important t1 x t1 etc values.
print("real ratings with estimated ratings: CS MINUS")
diag(corr.test(rating_est_minus,minus_scaled)$r)
print("real ratings with estimated ratings: CS MINUS (average for all trials)")
cor(rowMeans(rating_est_minus),rowMeans(minus_scaled))
print("real ratings with estimated ratings: CS PLUS")
diag(corr.test(rating_est_plus,plus_scaled)$r)
print("real ratings with estimated ratings: CS PLUS (average for all trials)")
cor(rowMeans(rating_est_plus),rowMeans(plus_scaled))
Recover
Here we are seeing if we can recover the same estimates using the simulated ratings. Basically run stan but using the estimated ratings instead of the real ones. See if we get the same alpha / beta parameters.
run stan model
#script
stanname='beta_mean1beta_PunSens.stan'
# data
flare_data_rec<-list(ntrials=ntrials,nsub=nsub,screamPlus = t(screamPlus), screamMinus= t(screamMinus),ratingsPlus=t(rating_est_plus),ratingsMinus=t(rating_est_minus),cdf_scale=cdf_scale)
flare_fit_rec <- model_run('full',stanname,flare_data_rec)
## get some basic output descriptions printed to screen
out_describe(flare_fit_rec,nsub)
Make alpha / beta datasets p/p
Use the summary of the stan model to extract the different parameters we want to try to use to recreate our data.
params_rec <- summary(flare_fit_rec)
alpha_est_rec <- data.frame(params_rec$summary[1:nsub,1])
beta_rec <- data.frame(params_rec$summary[(nsub+1):(nsub*2),1])
lambda_rec <- data.frame(params_rec$summary[(nsub*3+1):(nsub*4),1])
Correlate actual ratings with simulated ratings
use the simulated ratings per person that we have derived using our parameters and see how well they align with the real ratings…
Only showing the diaganols from corr.test package here to get the important t1 x t1 etc values.
print("original with recovered: ALPHA")
diag(corr.test(alpha_est_rec,alpha_est)$r)
print("original with recovered: BETA")
diag(corr.test(beta_rec,beta)$r)
print("original with recovered: LAMBDA")
diag(corr.test(lambda_rec,lambda)$r)
Beta is very poorly recovered here. Alpha and Lambda are recovered exceptionally well.
Will try a quick 2 beta mdoel with punishment sensitivity to see if this improves things.
Model 9: Punishment sensitivity 2 beta
Model
#script
stanname='beta_mean1beta_PunSens2Beta.stan'
flare_fit <- model_run('full',stanname,flare_data)
## get some basic output descriptions printed to screen
out_describe(flare_fit,nsub)
# extract fit data
summary_flare <- summary(flare_fit)
Create BIC from log likelihood
## extract log likelihood
flare_loglike <- extract_log_lik(flare_fit, parameter_name = "loglik", merge_chains = TRUE)
#calculate BIC
FLARe_bic<-bic(ntrials,-colMeans(flare_loglike),2) #number of parameters in that model e.g. 4)
## mean BIC as model comparisons tool:
print("Mean Bayesian information criterion for model")
mean(FLARe_bic)
Add to bar plot
mod_comp <- rbind(na.omit(mod_comp),c("Punishment sensitivity 2 beta",mean(FLARe_bic)))
mod_comp$BIC <- odp(as.numeric(mod_comp$BIC))
mod_comp <- as.data.frame(na.omit(mod_comp))
## plot function - create plot
plot_models(mod_comp)
Generate
Make alpha / beta datasets p/p
Use the summary of the stan model to extract the different parameters we want to try to use to recreate our data.
params <- summary(flare_fit)
alpha_est <- data.frame(params$summary[1:nsub,1])
beta_all <- data.frame(params$summary[(nsub+1):(nsub*3),1])
lambda <- data.frame(params$summary[(nsub*4+1):(nsub*5),1])
# divide beta into the two...
## p is 1, so the odd rows
beta_p <- data.frame(beta_all[ c(TRUE,FALSE), ]) # odd rows
beta_m <- data.frame(beta_all[ !c(TRUE,FALSE), ]) # even rows
names(alpha_est) <- "alpha"
names(beta_p) <- "beta_plus"
names(beta_m) <- "beta_minus"
names(lambda) <- "lambda"
Initialise empty datasets to hold the predicted ratings
rating_est_plus <- data.frame(matrix(ncol=ntrials,nrow=nsub))
rating_est_minus <- data.frame(matrix(ncol=ntrials,nrow=nsub))
# beta shape parameters
shape1p <- data.frame(matrix(ncol=ntrials,nrow=nsub))
shape1m <- data.frame(matrix(ncol=ntrials,nrow=nsub))
shape2p <- data.frame(matrix(ncol=ntrials,nrow=nsub))
shape2m <- data.frame(matrix(ncol=ntrials,nrow=nsub))
# V parameters (initialised at random value between 0.5 - 0.05 and 0.5+0.05)
vp <- data.frame(matrix(ncol=ntrials,nrow=nsub))
vm <- data.frame(matrix(ncol=ntrials,nrow=nsub))
vp[1] <- rnorm(nsub,0.5,0.025)
vm[1] <- rnorm(nsub,0.5,0.025)
# prediction error
dp <- data.frame(matrix(ncol=(ntrials-1),nrow=nsub))
dm <- data.frame(matrix(ncol=(ntrials-1),nrow=nsub))
Simulate ratings
Use our extracted parameters in place of estimating the same. Use the stan syntax
Populate our vplus and delta frames
use the alpha parameters we’ve extracted (alpha_est) d == delta (precdiction error) v == value (i.e. value for each stimulus)
for (p in 1:nsub){
for (t in 1:(ntrials-1)){
dp[p,t] <- screamPlus[p,t]*lambda[p,]-vp[p,t]
dm[p,t] <- screamMinus[p,t]*lambda[p,]-vm[p,t]
vp[p,t+1] <- vp[p,t]+alpha_est[p,1]*dp[p,t]
vm[p,t+1]<- vm[p,t]+alpha_est[p,1]*dm[p,t]
}
}
for (t in 1:ntrials){
shape1_Plus[t,p] = VPlus[t,p] * ((VPlus[t,p] * (1-VPlus[t,p])) / beta[p,1]);
shape1_Minus[t,p] = VMinus[t,p] * ((VMinus[t,p] * (1-VMinus[t,p])) / beta[p,2]);
shape2_Plus[t,p] = (1-VPlus[t,p]) * ((VPlus[t,p] * (1-VPlus[t,p])) / beta[p,1]);
shape2_Minus[t,p] = (1-VMinus[t,p]) * ((VMinus[t,p] * (1-VMinus[t,p])) / beta[p,2]);
ratingsPlus[t,p] ~ beta(shape1_Plus[t,p],shape2_Plus[t,p]);
ratingsMinus[t,p] ~ beta(shape1_Minus[t,p],shape2_Minus[t,p]);
}
} }
populate beta parameter shape frames
Use the new v frames and beta parameters.
Shape 1 and 2 are sufficient parameters for the beta distribution
for (p in 1:nsub){
for (t in 1:ntrials){
shape1p[p,t] = vp[p,t] * ((vp[p,t] * (1-vp[p,t])) / beta_p[p,1])
shape2p[p,t] = (1-vp[p,t]) * ((vp[p,t] * (1-vp[p,t])) / beta_p[p,1])
shape1m[p,t] = vm[p,t] * ((vm[p,t] * (1-vm[p,t])) / beta_m[p,1])
shape2m[p,t] = (1-vm[p,t]) * ((vm[p,t] * (1-vm[p,t])) / beta_m[p,1])
}
}
Estimate ratings
trying to use pbeta here (derives the distribution function givemn a set of probabilities)
For now, setting probabilities between 0 and 1 and taking the average…
for (p in 1:nsub){
for (t in 1:ntrials){
rating_est_plus[p,t] <- mean(rbeta(1000,shape1p[p,t],shape2p[p,t]))
rating_est_minus[p,t] <- mean(rbeta(1000,shape1m[p,t],shape2m[p,t]))
}
}
Correlate actual ratings with simulated ratings
use the simulated ratings per person that we have derived using our parameters and see how well they align with the real ratings…
Only showing the diaganols from corr.test package here to get the important t1 x t1 etc values.
print("real ratings with estimated ratings: CS MINUS")
diag(corr.test(rating_est_minus,minus_scaled)$r)
print("real ratings with estimated ratings: CS MINUS (average for all trials)")
cor(rowMeans(rating_est_minus),rowMeans(minus_scaled))
print("real ratings with estimated ratings: CS PLUS")
diag(corr.test(rating_est_plus,plus_scaled)$r)
print("real ratings with estimated ratings: CS PLUS (average for all trials)")
cor(rowMeans(rating_est_plus),rowMeans(plus_scaled))
The generating ratings are worse with this model overall.
Recover
Here we are seeing if we can recover the same estimates using the simulated ratings. Basically run stan but using the estimated ratings instead of the real ones. See if we get the same alpha / beta parameters.
run stan model
#script
stanname='beta_mean1beta_PunSens2Beta.stan'
# data
flare_data_rec<-list(ntrials=ntrials,nsub=nsub,screamPlus = t(screamPlus), screamMinus= t(screamMinus),ratingsPlus=t(rating_est_plus),ratingsMinus=t(rating_est_minus),cdf_scale=cdf_scale)
flare_fit_rec <- model_run('full',stanname,flare_data_rec)
## get some basic output descriptions printed to screen
out_describe(flare_fit_rec,nsub)
Make alpha / beta datasets p/p
Use the summary of the stan model to extract the different parameters we want to try to use to recreate our data.
params_rec <- summary(flare_fit_rec)
alpha_est_rec <- data.frame(params_rec$summary[1:nsub,1])
beta_all_rec <- data.frame(params_rec$summary[(nsub+1):(nsub*3),1])
lambda_rec <- data.frame(params_rec$summary[(nsub*4+1):(nsub*5),1])
# divide beta into the two...
## p is 1, so the odd rows
beta_p_rec <- data.frame(beta_all_rec[ c(TRUE,FALSE), ]) # odd rows
beta_m_rec <- data.frame(beta_all_rec[ !c(TRUE,FALSE), ]) # even rows
names(alpha_est_rec) <- "alpha"
names(beta_p_rec) <- "beta_plus"
names(beta_m_rec) <- "beta_minus"
names(lambda_rec) <- "lambda"
Correlate actual ratings with simulated ratings
use the simulated ratings per person that we have derived using our parameters and see how well they align with the real ratings…
Only showing the diaganols from corr.test package here to get the important t1 x t1 etc values.
print("original with recovered: ALPHA")
diag(corr.test(alpha_est_rec,alpha_est)$r)
print("original with recovered: BETA PLUS")
diag(corr.test(beta_p_rec,beta_p)$r)
print("original with recovered: BETA MINUS")
diag(corr.test(beta_m_rec,beta_m)$r)
print("original with recovered: LAMBDA")
diag(corr.test(lambda_rec,lambda)$r)
Interestingly this is much worse for the lambda. Also not great for beta. Only alpha remains ok. So overall the 1 beta is probably better even though the BIC is slightly worse.
Dual learning
Model 10: dual learning + punishment sensitivity ( 1 beta)
a la Toby paper - dual learning model.
Allows the stimuli to update based on the other stimulus outcomes.
This version also includes the punishment sensitivity multiplier as this was best so far
Model
#script
stanname='beta_DualLearn_PunSens_1beta.stan'
flare_fit <- model_run('min',stanname,flare_data)
## get some basic output descriptions printed to screen
out_describe(flare_fit,nsub)
# extract fit data
summary_flare <- summary(flare_fit)
Create BIC from log likelihood
## extract log likelihood
flare_loglike <- extract_log_lik(flare_fit, parameter_name = "loglik", merge_chains = TRUE)
#calculate BIC
FLARe_bic<-bic(ntrials,-colMeans(flare_loglike),2) #number of parameters in that model e.g. 4)
## mean BIC as model comparisons tool:
print("Mean Bayesian information criterion for model")
mean(FLARe_bic)
Add to bar plot
mod_comp <- rbind(na.omit(mod_comp),c("Dual Learning",mean(FLARe_bic)))
mod_comp$BIC <- odp(as.numeric(mod_comp$BIC))
mod_comp <- as.data.frame(na.omit(mod_comp))
## plot function - create plot
plot_models(mod_comp)
Rating consistency
A parameter that represents the rating consistency for multiple repeated / similar trials. I think it would be best to have one each for the CS+ and CS- given these differ in terms of how similar the trials are (CS- is always un-enforced for example). Can imagine consistency is a parameter that is concistent regardless of reinforcement / stimulus type though, especially in later phases. So worth testing both models.
A similar parameter is used in the charpentier et al. paper (see the last page before the references).
We will estimate this parameter as a factor that influences the overall shape of the choice probability distribution (beta distributiuon). It will do this via the sufficient parameters that are influences by stimulus value etc per trial.
note very unsure about this - need to check it out with Alex
\[shape1(stimulus) = (1 + exp(-\mu * VPlus[t,p] * ((VPlus[t,p] * (1-VPlus[t,p])) / beta[p,1]))^-1 \] where \[\mu = logit\\sensitivty\]
Where logit sensitivity effectively means consistency of rating consistency; higher valued should mean greater consistency.
Model
#script
stanname='beta_mean1beta_Consistency.stan'
flare_fit <- model_run('min',stanname,flare_data)
## get some basic output descriptions printed to screen
out_describe(flare_fit,nsub)
# extract fit data
summary_flare <- summary(flare_fit)
BIC is terrible
Create BIC from log likelihood
## extract log likelihood
flare_loglike <- extract_log_lik(flare_fit, parameter_name = "loglik", merge_chains = TRUE)
#calculate BIC
FLARe_bic<-bic(ntrials,-colMeans(flare_loglike),2) #number of parameters in that model e.g. 4)
## mean BIC as model comparisons tool:
print("Mean Bayesian information criterion for model")
mean(FLARe_bic)
Add to bar plot
mod_comp <- rbind(na.omit(mod_comp),c("Consistency",mean(FLARe_bic)))
mod_comp$BIC <- odp(as.numeric(mod_comp$BIC))
mod_comp <- as.data.frame(na.omit(mod_comp))
## plot function - create plot
plot_models(mod_comp)
Generalisation
NOTE TO SELF::
maybe generalise the prediction error NOT the value (so add some od deltaP to the VMinus calculation….)
some intro
Basically here we want to capture a parameter that estimates how much the learning from the reinforced stimulus influences responses to the ‘safe’ stimulus.
Basing my first effort on Norbury, Robbins & Seymour, 2018, and their finding that there is generalisation based on value and perceptual processes.
From their abstract
“We found that generalization of avoidance could be parsed into perceptual and value-based processes, and further, that value-based generalization could be subdivided into that relating to aversive and neutral feedback”…. “Further, generalization from aversive, but not neutral, feedback was associated with self-reported anxiety and intrusive thoughts. These results reveal a set of distinct mechanisms that mediate generalization in avoidance learning, and show how specific individual differences within them can yield anxiety.”
from introduction
“It is therefore possible that under-generalization of safety cues, as opposed to over-generalization of aversive cues, might be a contributing factor to susceptibility to disorders such as generalized anxiety”
Equations
I will basically replicate the visual and value generalisation equations.
Visual (i.e. possible identify confusion over the two stimuli):
\[V_c,_m =0.80*V_C,_m + 0.20*V_C,_p\]
Value:
\[G_s = 1/exp(\rho_o)^2 / 2*\delta))\] where \(_s\) is current stimulus, and \(_o\) is the other stimulus. \(\rho\) is the parameter governing shape ‘spikiness’" \(\delta\) is a free parameter that governs the width of the Gaussian function that governs generalisation. This parameter should probably differ depending on trial outcome (scream or neutral) \(\delta_s\) and \(\delta_n\).
They authors update their value by multiplying it by the generalisation of the current ‘state’ (stimulus). i.e. \(*G_s\) as the last term.
First we will use a single \(\delta\) value, rather than updating per trial depending on if it is scream + or -
So, for ours the following will be added to the punishment sensitivity single beta model.
One generalisation parameter
Generalisation:
\[G = 1/exp((\rho_m - \rho_p)^2 / (2*\delta^2))\]
generalisation per stimulus
Generalisation plus:
\[G_p = 1/exp((\rho_m - \rho_p)^2 / (2*\delta^2))\]
Generalisation minus:
\[G_m = 1/exp((\rho_p - \rho_m)^2 / (2*\delta^2))\] Value plus:
\[VPlus[t+1,p]=VPlus[t,p]+alpha[p]*PredErrorPlus[t,p]*G_p\] Value minus:
\[VMinus[t+1,p]=VMinus[t,p]+alpha[p]*PredErrorMinus[t,p]*G_p\]
additional things to try:
dependence on prediction error
\(\kappa\) will be a free parameter that indicates difference in dependence on prediction error history, and will make the v updates like so:
Value plus:
\[VPlus[t+1,p]=VPlus[t,p]+\kappa*alpha[p]*PredErrorPlus[t,p]*G_p\] Value minus:
\[VMinus[t+1,p]=VMinus[t,p]+\kappa*alpha[p]*PredErrorMinus[t,p]*G_p\]
updating learning rate per trial, per stimulus
the alpha would become
\[\alpha_t+1 = \eta | (PredError-V_p,_t)| + (1-\eta)*\alpha_t\]
Model 11: Visual generalisation
Allow visual generalistion between to change the value of the stimuli per trial.
Multiply own value by .8 and add the other stimuli value of .2 (see equations above).
Model
#script
stanname='beta_Visual_Gen.stan'
flare_fit <- model_run('min',stanname,flare_data_nolog)
## get some basic output descriptions printed to screen
out_describe(flare_fit,nsub)
# extract fit data
summary_flare <- summary(flare_fit)
Create BIC from log likelihood
## extract log likelihood
flare_loglike <- extract_log_lik(flare_fit, parameter_name = "loglik", merge_chains = TRUE)
#calculate BIC
FLARe_bic<-bic(ntrials,-colMeans(flare_loglike),2) #number of parameters in that model e.g. 4)
## mean BIC as model comparisons tool:
print("Mean Bayesian information criterion for model")
mean(FLARe_bic)
Add to bar plot
mod_comp <- rbind(na.omit(mod_comp),c("Visual Generalisation",mean(FLARe_bic)))
mod_comp$BIC <- odp(as.numeric(mod_comp$BIC))
mod_comp <- as.data.frame(na.omit(mod_comp))
## plot function - create plot
plot_models(mod_comp)
avoidance
Usinf volume per trial as an avoidance outcome and modelling as per Norbury et al in a sort of diffusion drift way. Basically updating value of avoid or not avoiding where avoid = = volume down per trial.
Might want to use a Pearce-Hall associatbility rule to update the learning rate here…
“According to this rule, the learning rate on each trial is determined by the absolute magnitude of past prediction errors, such that state-action value estimates are updated by more when previous outcomes have been more surprising, and by less when they were less surprising. This allows for learning in terms of modelled value adjustment to be greater when outcomes are more surprising (e.g. at the start of the task), but to be lesser (leading to more stable values) when outcomes are better predicted. A non-constant learning rate also ensures that parameters governing width of value-based generalization, which are assumed to be constant over the course of the task, are identifiable during parameter estimation (see below equations).”
Forgetting
this parameter is how much they retain what they learned over previous trials and use it to inform the current rating.
to do
investigte change point detection parameters (when reinforcement changes - i.e. moving acquisition to extinction) could do this or model the phases separately - check which best fits
add priors! These are what you expect the group to look like (i.e alpha is normally distributed around a mean of 0.5 with variance of 10 or something) LOOKUP R stan choice of priors. * can have informative or uninformative priors (i.e. agnostic or not)
Push any updates to github
Any push the updates to github
Unhash the series below if you made any changes.
## initialise bash directory and filename
stanname="punish_only.stan"
scriptdir="/Users/kirstin/Dropbox/SGDP/FLARe/FLARe_MASTER/Projects/Hierachal_modelling/Scripts"
## stage
#git add $scriptdir/$stanname
## push
#git push Bayes_modelling
LS0tCnRpdGxlOiAiSGllcmFjaGljYWwgY29tcHV0YXRpb25hbCBtb2RlbGxpbmcgLSBGTEFSZSIKYXV0aG9yOiAiS2lyc3RpbiBQdXJ2ZXMiCmRhdGU6ICIxIEFwcmlsIDIwMTkiCgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMgogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgaGlnaGxpZ2h0OiBtb25vY2hyb21lCiAgICB0aGVtZTogY2VydWxlYW4KICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgIAogIGh0bWxfbm90ZWJvb2s6CiAgICB0aGVtZTogY2VydWxlYW4KICAgIHRvYzogeWVzCiAgIAotLS0KCiMgSW50cm9kdWN0aW9uIHsudGFic2V0fQoKTGFiIGJvb2sgZm9yIGFuYWx5c2VzIHVzaW5nIGhpZXJhY2hhbCBjb21wdXRhdGlvbmFsIG1vZGVsbGluZyB0byBpZGVudGlmeSBwYXJhbWV0ZXJzIHRoYXQgZGVmaW5lIHRoZSBiZXN0IG1vZGVsIG9mIGxlYXJuaW5nIGFzIGl0IGFwcGxpZXMgdG8gZmVhciBjb25kaXRpb25pbmcgYWNxdWlzaXRpb24gYW5kIGV4dGluY3Rpb24gdXNpbmcgRkxBUmUgZmVhciBjb25kaXRpb25pbmcgZGF0YS4gCkxvbmcgYWJzdHJhY3QsIGp1c3RpZmljYXRpb24gYW5kIGFuYWx5c2lzIHBsYW4gZm91bmQgaW4gcHJlbGltIG1hbnVzY3JpcHQgW2hlcmVdKFtodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9kb2N1bWVudC9kLzFKaFZDZjBqbFhGd1hZUTJralMzZnBsN21ZZXhEY1VMbjdMMVpnSjZOb2x3L2VkaXQ/dXNwPXNoYXJpbmddKQoKSW4gc2hvcnQ6CgojIyBBaW1zICAgIAogICAgIAoxLiAgSWRlbnRpZnkgbW9kZWwgb2YgbGVhcm5pbmcgYmFzZWQgb24gYSBwcmlvcmkgaHlwb3RoZXNlcyB0aGF0IGJlc3QgZml0cyB0aGUgdHJhamVjdG9yaWVzIG9mIGZlYXIgcmVsZXZhbnQgbGVhcm5pbmcgaW4gb3VyIEZMQVJlIGRhdGFzZXQKICAgICAgKyBVc2UgYWxsIGZpcnN0IHdlZWsgZGF0YSBmcm9tIFZhbGlkYXRpb24sIGFwcCBUUlQsIGxhYiBUUlQsIFBpbG90LCBIZWFkcGhvbmVzIChuID0gMjIzIGFmdGVyIGV4Y2x1c2lvbnMpCiAgICAgICsgSW5jbHVkZSBBY3F1aXNpdGlvbiwgZXh0aW5jdGlvbiAodHJhamVjdG9yaWVzIHJlcHJlc2VudGluZyBmZWFyIGxlYXJuaW5nIGFuZCB0cmVhdG1lbnQpCiAgICAgICsgSWRlbnRpZnkgcGFyYW1ldGVycyB0aGF0IGRlZmluZSB0aGVzZSB0cmFqZWN0b3JpZXMKICAgICAgICAgICsgZS5nLiBMZWFybmlnbiByYXRlLCBwbGF0ZWF1LCBmaXJzdCBhbWJpZ3VvdXMgdHJpYWwgZXRjLgogICAgICAgICAgCjIuICBDcm9zcyB2YWxpZGF0ZSBiZXN0IGZpdHRpbmcgbW9kZWwgaW4gVEVEUyBkYXRhCgozLiAgQXJlIHRoZXNlIHBhcmFtZXRlcnMgYXNzb2NpYXRlZCB3aXRoIG90aGVyIGVtYXN1cmVzIG9mIGluZHNpdmlkdWFsIGRpZmZlcmVuY2VzIGluIG91ciBkYXRhc2V0cz8KICAgICAgKyBQZXJzb25hbGl0eSAoTmV1cm90aWNpc20pCiAgICAgICsgQ3VycmVudCBhbnhpZXR5IHN5bXB0b21zIChHQUQtNykgLSBlcXVpdmFsZW50IG9mIGJhc2VsaW5lIHN5bXB0b21zIChDaHJpcyArIE1lZyBhbmFseXNlcykKICAgICAgKyBMaWZldGltZSAvIHRyYWl0IGFueGlldHkgKFNUQUkgLyBBU0kgLSBGTEFSZSBhbmFseXNlcykKICAgICAgKyBDdXJyZW50IGRlcHJlc3Npb24gc3ltcHRvbXMgKFBIUS05KSAtICBlcXVpdmFsZW50IG9mIGJhc2VsaW5lIHN5bXB0b21zIChDaHJpcyArIE1lZyBhbmFseXNlcykKICAgICAgKyBJbnRlcnByZXRhdGlvbiBiaWFzZXMgKElVUywgQVNTSVEgLSBGTEFSZSBhbmFseXNlcykKICAgICAgKyBTRVMgKE1lZyBJQVBUOiBiZW5lZml0cywgZW1wbG95bWVudCBldGMpIAogICAgICArIEdlbmRlciAoTWVnIGFuYWx5c2VzKQogICAgICArIEVtb3Rpb24gcmVndWxhdGlvbiBwcm9maWxlIChwb3RlbnRpYWxseSBMQ0EgYmFzZWQ/KQoKCiMjIEltcGFjdCBhbmQgcmVsZXZhbmNlCgpgYGAKRXZpZGVuY2UgZnJvbSBib3RoIGh1bWFuIChSaWNodGVyIGV0IGFsLiwgMjAxMikgYW5kIHJvZGVudCAoR2FsYXR6ZXItTGV2eSwgQm9uYW5ubywgQnVzaCwgJiBMZURvdXgsIDIwMTMpIHN0dWRpZXMgc3VnZ2VzdCB0aGF0IHRyYWplY3RvcmllcyBvZiBob3cgd2UgbGVhcm4gYW5kIGV4dGluZ3Vpc2ggZmVhciBkaWZmZXIgYmV0d2VlbiBpbmRpdmlkdWFscy4gRGlmZmVyZW50IHRyYWplY3RvcmllcyBvZiBmZWFyIGFuZCBleHRpbmN0aW9uIGhhdmUgYWxzbyBiZWVuIGZvdW5kIHVzaW5nIGZlYXIgY29uZGl0aW9uaW5nIHN0dWRpZXMgKGUuZy4gRHVpdHMgZXQgYWwuLCAyMDE2KSwgYSBnb29kIG1vZGVsIGZvciB0aGUgbGVhcm5pbmcgb2YsIGFuZCB0cmVhdG1lbnQgZm9yLCBmZWFyIGFuZCBhbnhpZXR5IGRpc29yZGVycy4gSXQgaXMgbGlrZWx5IHRoYXQgdGhlc2UgdHJhamVjdG9yaWVzIG9mIGZlYXIgZXh0aW5jdGlvbiBtaWdodCBwcmVkaWN0IG91dGNvbWVzIGluIGV4cG9zdXJlLWJhc2VkIGNvZ25pdGl2ZSBiZWhhdmlvdXJhbCB0aGVyYXB5IChLaW5kdCwgMjAxNCkuIAogCklkZW50aWZ5aW5nIHBhcmFtZXRlcnMgdGhhdCBwcmVkaWN0IGluZGl2aWR1YWwgdHJhamVjdG9yaWVzIG9mIGZlYXIgbGVhcm5pbmcgYW5kIGV4dGluY3Rpb24gd2lsbCBlbmFibGUgdXMgdG8gaGFybmVzcyBmZWFyIGNvbmRpdGlvbmluZyBkYXRhIG1vcmUgZWZmZWN0aXZlbHkgdG8gYWlkIGluIHVuZGVyc3RhbmRpbmcgbWVjaGFuaXNtcyB1bmRlcmx5aW5nIHRoZSBkZXZlbG9wbWVudCBvZiBhbmQgdHJlYXRtZW50IGZvciBhbnhpZXR5IGRpc29yZGVycy4gV2l0aCBtb3JlIGFjY3VyYXRlIG1vZGVscyBvZiB0aGVzZSBwcm9jZXNzZXMsIHRoZSBwb3RlbnRpYWwgdG8gdXNlIGZlYXIgY29uZGl0aW9uaW5nIHBhcmFkaWdtcyB0byBwcmVkaWN0IHRob3NlIG1vc3QgYXQgcmlzayBvZiBkZXZlbG9waW5nIGFuIGFueGlldHkgZGlzb3JkZXIsIGFuZCB0aG9zZSB3aG8gbWlnaHQgcmVzcG9uZCBiZXN0IHRvIGV4cG9zdXJlLWJhc2VkIHRyZWF0bWVudHMsIGdyZWF0bHkgaW1wcm92ZXMuCmBgYAoKIyMgVXNlZnVsIHJlZmVyZW5jZXMKCltTdXR0b24gYW5kIEJhcnRvIFJlaW5mb3JjZW1lbnQgTGVhcm5pbmddKGh0dHA6Ly9pbmNvbXBsZXRlaWRlYXMubmV0L2Jvb2svUkxib29rMjAxOC5wZGYpIC0gVGV4dGJvb2sgb24gcmVpbmZvcmNlbWVudCBsZWFybmluZyAgIApbQW54aWV0eSBwcm9tb3RlcyBtZW1vcnkgZm9yIG1vb2QtY29uZ3J1ZW50IGZhY2VzIGJ1dCBkb2VzIG5vdCBhbHRlciBsb3NzIGF2ZXJzaW9uIChDaGFycGVudGllci4uLlJvYmluc29uLCAyMDE1KV0oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9zcmVwMjQ3NDYucGRmKSAtIEdvb2QgZXhhbXBsZSBvZiBhIHNlbnNpdGl2aXR5IGxlYXJuaW5nIHBhcmFtZXRlciAgICAKW0h5cG90aGVzZXMgQWJvdXQgdGhlIFJlbGF0aW9uc2hpcCBvZiBDb2duaXRpb24gV2l0aCBQc3ljaG9wYXRob2xvZ3kgU2hvdWxkIGJlIFRlc3RlZCBieSBFbWJlZGRpbmcgVGhlbSBJbnRvIEVtcGlyaWNhbCBQcmlvcnMgKE1vdXRvdXNzaXN0IGV0IGFsLiwgMjAxOCldKGh0dHBzOi8vd3d3LmZyb250aWVyc2luLm9yZy9hcnRpY2xlcy8xMC4zMzg5L2Zwc3lnLjIwMTguMDI1MDQvZnVsbCkgLSBJbmNsdWRpbmcgdmFyaWFibGVzIG9mIGludGVyZXN0IChlLmcuIGFueGlldHkpIGluIHRoZSBtb2RlbCAgICAKCgpUb2J5IFdpc2UgaGFzIGp1c3Qgc3VibWl0dGVkIGFuIGF2ZXJzaXZlIGxlYXJuaW5nIHBhcGVyIGluY29ycG9yYXRpbmcgYmV0YSBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb25zIGluIHRoZSBiZXN0IG1vZGVsIGZvciB1bmNlcnRhaW4gbGVhcm5pbmcgcGFyYW1ldGVycyBldGMuCgpBIGNvcHkgb2YgdGhpcyBpcyAhW2hlcmVdKC9Vc2Vycy9raXJzdGluL0Ryb3Bib3gvU0dEUC9GTEFSZS9QREZzL3VuY2VydGFpbnR5X2F0dGVudGlvbl9wYXBlcl9QTG9TQ0IucGRmKQoKCiMjIEFuYWx5c2lzIHBsYW4gCgoxLiAgRGVmaW5lIHNldCBvZiBhIHByaW9yaSBtb2RlbHMgbW92aW5nIGZyb20gc2ltcGxlIHRvIG1vcmUgY29tcGxleCAgCiAgICAgICsgU29tZSBwYXJhbWV0ZXJzIHRvIGluY2x1ZGU6IAogICAgICAgICsgUmF0ZSBvZiBsZWFybmluZyAoc29tZXRpbWVzIHdpdGggcHVuaXNobWVudCByZWluZm9yY2VtZW50KQogICAgICAgICsgU2Vuc2l0aXZpdHkgdG8gcHVuaXNobWVudAogICAgICAgICsgUHJlLWV4aXN0aW5nIGFueGlldHkKICAgICAgICArIFNFUz8gR2VuZGVyPyAgICAKICAgICAgICAKCiAgICAgICAgCjIuICBSdW4gZWFjaCBtb2RlbCBhbmQgY29tcGFyZSBmaXQgaW4gRkxBUmUgcHJlIFRFRFMgZGF0YQogICAgICArIFVzZSBMb2cgbGlrZWxpaG9vZCBhbmQgQklDIGV0Yy4gICAgCiAgICAgIAogICAgICAKMy4gIFNlbGVjdCBiZXN0IGZpdHRpbmcgbW9kZWwgICAKCgo0LiAgRXh0cmFjdCBpbmRpdmlkdWFsIGRhdGEgZm9yIGxlYXJuaW5nIHBhcmFtZXRlcnMgZnJvbSB0aGlzIG1vZGVsIGFuZCBzZWUgd2hhdCBmYWN0b3JzIGJlc3QgcHJlZGljdCBpdAogICAgICArIEFueGlldHkgKGlmIGFueGlldHkgaXNudCBiZXN0IGFzIHBhcnQgb2YgdGhlIG1vZGVsKQogICAgICArIEludGVycHJldGF0aW9uIGJpYXNlcwogICAgICArIFRvbGVyYW5jZSBvZiB1bmNlcnRhbnR5CiAgICAgICsgQ29nbml0aXZlIGVtb3Rpb25hbCBjb250cm9sCiAgICAgICsgZW1vdGlvbmFsIGF0dGVudGlvbmFsIGNvbnRyb2wgCiAgICAgICsgU0VTPwogICAgICArIEdlbmRlcj8gICAgCiAgICAgIAoKNC4gIFJ1biBhbGwgbW9kZWxzIGFnYWluIGluIEZMQVJlIFRFRFMKICAgICAgKyBEZWNpZGUgaWYgdGhlIHNhbWUgbW9kZWwgYmVzdCBmaXRzIHRoZSBkYXRhIGFnYWluLgogICAgICArIFNlZSBpZiB3ZSBnZXQgc2ltaWxhciByZXN1bHRzIGZyb20gdGhlIHBhcmFtZXRlciBwcmVkaWN0aW9uICAgCiAgICAgIAogICAgCgoKV2lsbCB1c2UgYSBjb21iaW5hdGlvbiBvZiBgUi5WZXJzaW9uKDMuNS4xKWAsIGBSU3RhbiAoVmVyc2lvbiAyLjE4LjIsIEdpdFJldjogMmUxZjkxM2QzY2EzKWAgYW5kIGBoQmF5ZXNETSBwYWNrYWdlIGluIFIgKDMuNS4xKWAgW0FobiwgVy4tWS4sIEhhaW5lcywgTi4sICYgWmhhbmcsIEwuICgyMDE3KS4gUmV2ZWFsaW5nIG5ldXJvLWNvbXB1dGF0aW9uYWwgbWVjaGFuaXNtcyBvZiByZWluZm9yY2VtZW50IGxlYXJuaW5nIGFuZCBkZWNpc2lvbi1tYWtpbmcgd2l0aCB0aGUgaEJheWVzRE0gcGFja2FnZS4gQ29tcHV0YXRpb25hbCBQc3ljaGlhdHJ5LCAxLCAyNC01Ny5dKGh0dHBzOi8vZG9pLm9yZy8xMC4xMTYyL0NQU1lfYV8wMCksIHdoaWNoIHVzZXMgUlN0YW4KCgojIyBNb2RlbGxpbmcgbm90ZXMgey50YWJzZXR9CgojIyMgSW50dWl0aW9uCgoKRGlzY3Vzc2lvbiB3aXRoIFZpbmNlIFZhbHRvbiBhbmQgQWxleCBQaWtlIGFib3V0IHRoZSBiZXN0IHdheSB0byBmaXQgdGhpcyBtb2RlbC4gQXMgdGhlIG9ic2VydmVkIG91dGNvbWVzIChleHBlY3RhbmN5IHJhdGluZ3MpIGFyZSBub24gYmluYXJ5IGFuZCBhcmUgcmVsYXRlZCB0byBlYWNob3RoZXIgKGkuZS4gYXMgeW91IGJlY29tZSBtb3JlIGxpa2VseSB0byBzZWxlY3QgOSwgeW91IGJlY29tZSBsZXNzIGxpa2VseSB0byBzZWxlY3QgMSkgd2Ugc2hvdWxkIGNvbnNpZGVyIGVhY2ggdHJpYWwgZm9yIGVhY2ggcGVyc29uIGZvciBlYWNoIHN0aW11bHVzIGFzIGEgY29uc3RhbnRseSB1cGRhdGluZyBiZXRhIGRpc3RyaWJ1dGlvbi4gc28geW91IG1pZ2h0IHNlZSBhIHBhdHRlcm4gbGlrZSB0aGlzIGZvciB0aGUgQ1MrIGluIGFjcSBmb3IgZXhhbXBsZS4KClNvLCBiZXN0IG1vZGVsIGlzIGxpa2VseSB0byBiZSBvbmUgdXNpbmcgYmV0YSBkaXN0cmlidXRpb25zIHRoYXQgc2hvdyB0aGUgcHJvYmFiaWxpdHkgZGlzdHJpYnV0aW9uIGZvciBlYWNoIHJhdGluZy4gCgpXZSBjYW4gdXNlIHN1ZmZpY2llbnQgcGFyYW1ldGVycyB0byBkZXNjcmliZSB0aGVzZSAoaS5lLiBtZWFuIC8gc2Qgb3IgcG9zc2libHkgdGhlIG1vZGUpCgpBIHVzZWZ1bCBpbnR1aXRpb24gb2YgdGhlIGJldGEgZGlzdHJpYnRpb24gY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL3N0YXRzLnN0YWNrZXhjaGFuZ2UuY29tL3F1ZXN0aW9ucy80Nzc3MS93aGF0LWlzLXRoZS1pbnR1aXRpb24tYmVoaW5kLWJldGEtZGlzdHJpYnV0aW9uKQoKYW5kIGEgdXNlZnVsIHdlYnNpdGUgW2hlcmVdKGh0dHBzOi8vbWF0dGhld2RoYXJyaXMuY29tLzIwMTYvMTAvMTgvZXN0aW1hdGluZy1hLWJldGEtZGlzdHJpYnV0aW9uLXdpdGgtc3Rhbi1obWMvKQoKKnNjYWxpbmcqCgpXZSBjYW4gc2NhbGUgdGhlIGJldGEgYnkgaG93IGF2ZXJzaXZlIHBhcnRpY2lwYW50cyBmaW5kIHRoZSBzaG9jay4gaS5lLiBpdCBtaWdodCB1cGRhdGUgdGhlaXIgbGVhcm5pbmcgYXMgaWYgdGhlcmUgd2FzIC41IGEgc2hvY2sgb3IgMS41IG9mIGEgc2hvY2sgZGVwZW5kaW5nIG9uIHRoZWlyIG93biBzZW5zaXRpdml0eSB0byB0aGUgYXZlcnNpdmVuZXNzIC8gcHVuaXNobWVudC4KCiphbHBoYSoKCipnZW5lcmFsaXNhdGlvbioKCldlIGNhbiBkbyB0aGlzIHdpdGggYSBzaW5nbGUgYmV0YSBkaXN0cmlidXRpb24gZm9yIGVhY2ggcGhhc2UgKGNvbGxhcHNpbmcgb3ZlciB0aGUgdHdvIHN0aW11bGkpLiBUaGlzIHdvdWxkIGJlIGFraW4gdG8gYSBwZXIgcGhhc2UgZ2VuZXJhbGlzYXRpb24gcGFyYW1ldGVyIGluIHRoYXQgaXQgd2lsbCBiZSBzbWFsbGVyIGlmIHRoZXkgdGVuZCB0byBjaG9vc2UgdGhlIHNhbWUgZXhwZWN0YW5jeSBmb3IgYm90aCBzdGltdWxpIGFuZCBsYXJnZXIgaWYgdGhleSB0ZW5kIHRvIGNob29zZSB2ZXJ5IGRpZmZlcmVudGx5IGZvciBib3RoIHN0aW11bGkuIAoKKioqSG93ZXZlcioqKiwgYmVjYXVzZSB0aGVzZSB2YXJpYWJsZXMgYXJlIG5vdCByZWFsbHkgZXF1aXZhbGVudCAoaS5lIHRoZSByZWluZm9yY2VtZW50IHJhdGUgaXMgZGlmZmVyZW50IGZvciBib3RoLCBhbmQgd2UgdXNlIHRoaXMgaW4gdGhlIG1vZGVsKSAgIAoKU28gaW5zdGVhZCB3ZSBjYW4gY3JlYXRlIGEgcGFyYW1hdGVyIHdoaWNoIGlzIHRoZSB2YWx1ZSBvZiBjcy0gd2VpZ2h0ZWQgYnkgc29tZSB2YWx1ZSBvZiB0aGUgY3MrLiBIb3cgbXVjaCBlYWNoIGluZGl2aWR1YWwgd2VpZ2h0cyBieSB0aGUgQ3MrIGNhbiBiZSBmcmVlbHkgZXN0aW1hdGVkIGJ5IHRoZSBtb2RlbCBhbmQgY2FuIGJlIHRoZSBnZW5lcmFsaXNhdGlvbiBwYXJhbWV0ZXIuCgpTbyB0aGlzIHdvdWxkIGJlIHZtaW51cyA9IHZtaW51cyArICh3KXZwbHVzICh3aGVyZSB0aGUgdyBwYXJhbWV0ZXIgaXMgdGhlIGZyZWVseSBlc3RpbWF0ZWQgcGFyYW1ldGVyIHBlciBwZXJzb24pCgoKKnBlciBzdGltdWx1cyoKV2UgcHJvYmFibHkgd2FudCB0byBtb2RlbCBjcysgYW5kIGNzLSBzZXBhcmF0ZWx5IHRvbyAtIHNvIGhhdmUgYSBiZXRhIGRpc3RyaWJ1dGlvbiBjaGFyYWN0ZXJpc2VkIGJ5IHN1ZmZpY2llbnQgcGFyYW1ldGVycyBmb3IgZWFjaC4KCgoKKnBlciB0cmlhbCoKCkFsbCBvZiB0aGUgYWJvdmUgY2FuIHRoZW4gYWxzbyBiZSBkb25lIHdpdGggdXBkYXRpbmcgcGVyIHRyaWFsLiAKCipsZWFreSBiZXRhKgoKd2UgYWxzbyBuZWVkIGEgbW9kZWwgdGhhdCBpbmNvcnBvcmF0ZXMgJ2xlYWsnLiAqKmkuZS4qKiBsZWFybmluZyBsZWFrIC0gbGlrZWx5IHRoYXQgcGFydGljaXBhbnRzIHdpbGwgdXBkYXRlIG1vcmUgYmFzZWQgb24gbW9yZSByZWNlbnQgdHJpYWxzIGFuZCBsZWFybiBsZXNzIGZyb20gdGhlIG1vcmUgZGlzdGFudCB0cmlhbHMgYXMgdGltZSBwcm9ncmVzc2VzLiBTZWUgVG9ieSdzIHBhcGVyICFbaGVyZV0oL1VzZXJzL2tpcnN0aW4vRHJvcGJveC9TR0RQL0ZMQVJlL1BERnMvdW5jZXJ0YWludHlfYXR0ZW50aW9uX3BhcGVyX1BMb1NDQi5wZGYpIGZvciBtb3JlLiAKCip1bmNlcnRhaW50eSoKCldlIHNob3VsZCBjb25zaWRlciBpbmNvcnBvcnRhdGluZyBhIHBhcmFtZXRlciB0aGF0IG1hcHMgdG8gcGFydGljaXBhbnQgdW5jZXJ0YWludHkgYWJvdXQgb3V0Y29tZXMuIAoKKmFueGlldHkqCgpNaWdodCBiZSB3b3J0aCBpbmNvcnBvcmF0aW5nIHRoaXMgYXMgYSBtb2RlbCBwYXJhbWF0ZXIgLyBmZWF0dXJlLiBSZWFkIHRoaXMgZm9yIG1vcmUuCgpbSHlwb3RoZXNlcyBBYm91dCB0aGUgUmVsYXRpb25zaGlwIG9mIENvZ25pdGlvbiBXaXRoIFBzeWNob3BhdGhvbG9neSBTaG91bGQgYmUgVGVzdGVkIGJ5IEVtYmVkZGluZyBUaGVtIEludG8gRW1waXJpY2FsIFByaW9ycyAoTW91dG91c3Npc3QgZXQgYWwuLCAyMDE4KV0oaHR0cHM6Ly93d3cuZnJvbnRpZXJzaW4ub3JnL2FydGljbGVzLzEwLjMzODkvZnBzeWcuMjAxOC4wMjUwNC9mdWxsKQoKIyMjIExvZyBsaWtlbGlob29kIG5vdGVzCgpBcyB3ZSBhcmUgdXNpbmcgYSBiZXRhIGRpc3RyaWJ1dGlvbiwgd2Ugd2lsbCBjYWxjdWxhdGUgbG9nIGxpa2VsaWhvb2QgYmFzZWQgb24gdGhlIHByb2JhYmlsaXR5IGZ1bmN0aW9uIGZvciB0aGUgZGlzdHJpYnV0aW9uIChpLmUuIHdoZXJlIHdpbGwgdGhlIHBlYWsgb2YgdGhlIHNoYXBlIGJlKSBnaXZlbiB0aGUgcGFydGljaXBhbnRzIHJlc3BvbnNlIGF0IGVhY2ggdHJpYWwuIFNvIHdpbGwgYWRkIHRoZSBwcm9iYWJpbGl0eSBkZW5zaXR5IGZ1bmN0aW9uIGdpdmVuIGVhY2ggdHJpYWwgcmVzcG9uc2UgdHJpYWwgYnkgdHJpYWwgZm9yIGVhY2ggb2YgdGhlIENTKyBhbmQgLSBzdW1tZWQgdG9nZXRoZXIuCgpXaWxsIG9idGFpbiAxIGxvZyBsaWtlbGlob29kIGFuZCB0aGVuIDEgcGVyIHRyaWFsIGFuZCBhZGQgdG9nZXRoZXIgdG8gbWFrZSBzdXJlIHRoYXQgdGhlc2UgYXJlIGNvbXBhcmFibGUuCgoKdGhlIGJhc2ljIHN0YW4gdGVybWlub2xvZ3kgZm9yIHRoaXMgaXMgYmVsb3c6IAoKPj4gYmV0YV9scGRmKHJhdGluZ1t0LHBdfHNoYXBlMVt0LHBdLHNoYXBlMlt0LHBdKQoKd2hlcmUgYmV0YV9scGRmIGlzIHRoZSBwcm9iYWJpbGl0eSBkZW5zaXR5IGdpdmVuIHRoZSByYXRpbmcgbWFkZSBhbmQgZWFjaCBvZiB0aGUgdHdvIGJldGEgZGlzdHJpYnV0aW9uIHNoYXBlIHBhcmFtZXRlcnMgdGhhdCB3ZSBlc3RpbWF0ZS4KClRoaXMgaXMgd2hhdCB3ZSB3aWxsIHVzZSB0byBjb21wYXJlIG1vZGVscy4KCiMjIyBUZXJtaW5vbG9neQoKKlYqID09ICd2YWx1ZScuIEJhYXNpY2FsbHkgYSBwYXJhbWV0ZXIgdGhhdCBpcyBhYm91dCB0aGUgc2FsaWVuY2Ugb2YgdGhlIHN0aW11bHVzIGF0IGFueSBnaXZlbiBwb2ludC4gICAgCiphbHBoYSogPT0gJ2xlYXJuaW5nIHJhdGUnLiBBIHBhcmFtZXRlciB0aGF0IGRlc2NyaWJlcyBob3cgc2Vuc2l0aXZlIHBlb3BsZSBhcmUgdG8gdXBkYXRpbmcgdGhlaXIgbGVhcm5pbmcuIFNvIGEgZmFzdCBsZWFybmluZyByYXRlIG1lYW5zIHRoYXQgbGVhcm5pbmcgb24gYW55IGdpdmVuIHRyaWFsIGlzIHdlaWdodGVkIG1vcmUgYmFzZWQgb24gdGhlIHRyaWFscyBpbW1lZGlhdGx5IHByZWNlZGluZyB0aGFuIHBhc3Qgb25lcywgYW5kIGEgc2xvdyBsZWFybmluZyByYXRlIG1lYW5zIHRoYXQgYWxsIHBhc3QgZXZlbnRzIGluZmx1ZW5jZSBsZWFybmluZyBtb3JlIGV2ZW5seS4gIEFsZXgncyB0ZW5uaXMgYW5hbG9neSBpcyBnb29kIGhlcmUgKEZlZGVyZXIgLSBzdGFibGUgcGxheWVyLCBjYW4gcHJlZGljdCBhIHdpbiBiYXNlZCBvbiBhbGwgbWF0Y2hlczsgTXVycmF5IC0gdm9sYXRpbGUgcGxheWVyOyBoaXMgbGFzdCBtYXRjaCBpcyBiZXN0IHByZWRpY3RvciBvZiBuZXh0IG1hdGNoIHBlcmZvcm1hbmNlKS4gCipiZXRhKiA9PSAnY29uZmlkZW5jZScuIFRoaXMgaXMgc29ydCBvZiBhbiBlcnJvciB0ZXJtIC0gaG93IG11Y2ggdmFyaWFuY2UgaW4gcmF0aW5nIGNob2ljZSBpcyB0aGVyZSBmb3IgZWFjaCBwZXJzb24vdHJpYWwuIENhbiBiZSB0aG91Z2h0IG9mIGFzIHRoZSB2YXJpYW5jZSwgb3IgYmV0YV4yIGFzIHRoZSBzZC4gICAKCkNhbiBiZSBjb25mdXNpbmcgYXMgd2UgYXJlIHVzaW5nIGJldGEgZGlzdHJpYnV0aW9ucyAoZGlmZmVyZW50IHRoaW5nKSB3aGljaCBoYXMgdHdvIHN1ZmZpY2llbnQgcGFyYW1ldGVycyBhICsgYikuCgojIyMgQmV0YSBkaXN0cmlidXRpb24gdmlzdWFsaXNhdGlvbgoKYW5kIGhvdyB0aGV5IGNoYW5nZSBkZXBlbmRpbmcgb24gd2hldGhlciB5b3UgY2hhbmdlIHRoZSBiZXRhIG9yIGFscGhhIHBhcmFtZXRlcnMuCgohW0EgcmVhbGx5IG5pY2Ugc3VtbWFyeSB2aXN1YWxpc2F0aW9uXSgvVXNlcnMva2lyc3Rpbi9Ecm9wYm94L1NjcmVlbnNob3RzL2JldGFfZGlzdC5wbmcpCgpIZXJlIGFyZSBzb21lIHNpbXVsYXRpb25zIEkgY2FuIGNoYW5nZSBhbmQgcGxheSB3aXRoIHRoZSBpbGx1c3RyYXRlIHRoZSBzYW1lIHNvcnQgb2YgdGhpbmcuIAoKCmBgYHtyIGJldGEgc2ltdWxhdGlvbnMsZWNobz1GfQp4IDwtIHNlcSgwLCAxLCBsZW5ndGggPSAyMSkKZGJldGEoeCwgMSwgMSkKcGJldGEoeCwgMSwgMSkKCiMjIFZpc3VhbGl6YXRpb24sIGluY2x1ZGluZyBsaW1pdCBjYXNlczoKcGwuYmV0YSA8LSBmdW5jdGlvbihhLGIsIGFzcCA9IGlmKGlzTGltKSAxLCB5bGltID0gaWYoaXNMaW0pIGMoMCwxLjEpKSB7CiAgaWYoaXNMaW0gPC0gYSA9PSAwIHx8IGIgPT0gMCB8fCBhID09IEluZiB8fCBiID09IEluZikgewogICAgZXBzIDwtIDFlLTEwCiAgICB4IDwtIGMoMCwgZXBzLCAoMTo3KS8xNiwgMS8yK2MoLWVwcywwLGVwcyksICg5OjE1KS8xNiwgMS1lcHMsIDEpCiAgfSBlbHNlIHsKICAgIHggPC0gc2VxKDAsIDEsIGxlbmd0aCA9IDEwMjUpCiAgfQogIGZ4IDwtIGNiaW5kKGRiZXRhKHgsIGEsYiksIHBiZXRhKHgsIGEsYiksIHFiZXRhKHgsIGEsYikpCiAgZiA8LSBmeDsgZltmeCA9PSBJbmZdIDwtIDFlMTAwCiAgbWF0cGxvdCh4LCBmLCB5bGFiPSIiLCB0eXBlPSJsIiwgeWxpbT15bGltLCBhc3A9YXNwLAogICAgICAgICAgbWFpbiA9IHNwcmludGYoIltkcHFdYmV0YSh4LCBhPSVnLCBiPSVnKSIsIGEsYikpCiAgYWJsaW5lKDAsMSwgICAgIGNvbD0iZ3JheSIsIGx0eT0zKQogIGFibGluZShoID0gMDoxLCBjb2w9ImdyYXkiLCBsdHk9MykKICBsZWdlbmQoInRvcCIsIHBhc3RlMChjKCJkIiwicCIsInEiKSwgImJldGEoeCwgYSxiKSIpLAogICAgICAgICBjb2w9MTozLCBsdHk9MTozLCBidHkgPSAibiIpCiAgaW52aXNpYmxlKGNiaW5kKHgsIGZ4KSkKfQoKIyMgY2hhbmdlIGFscGhhCgpwcmludCgic3RhYmxlIGJldGEsIGluY3JlYXNpbmcgYWxwaGEiKQpwbC5iZXRhKDUsIDUpCnBsLmJldGEoOCwgNSkKcGwuYmV0YSgxMCwgNSkKcGwuYmV0YSgxMiwgNSkKcGwuYmV0YSgxOCwgNSkKCgojIyBjaGFuZ2UgYmV0YQpwcmludCgic3RhYmxlIGFscGhhLCBpbmNyZWFzaW5nIGJldGEiKQpwbC5iZXRhKDUsIDUpCnBsLmJldGEoNSwgOCkKcGwuYmV0YSg1LCAxMCkKcGwuYmV0YSg1LCAxMikKcGwuYmV0YSg1LCAxNSkKCgpgYGAKCiMjIyBNb2RlbHMgdG8gd3JpdGUgLyBydW4KCldpbGwgcHJvYmFibHkgZG8gYWxsIHBlciB0cmlhbC4gV2lsbCBkbyBhbiBlYXJseSBzZW5zaXRpdml0eSBjaGVjayB0byBjb25maXJtIHRoaXMuCgoKMS4gIFNpbmdsZSBiZXRhLCBubyBzY2FsaW5nICAgCjIuICBTaW5nbGUgYmV0YSwgbm8gc2NhbGluZyBwZXIgdHJpYWwuICAgCioqKiBBdCB0aGlzIHBvaW50LCBjb21wYXJlIHRoZSB0d28gYWJvdmUuIEVuc3VyZSB0aGUgcGVyIHRyaWFsIGZpdHMgYmV0dGVyLCBhbmQgaWYgaXQgZG9lcyB0aGVuIGRvIGFsbCBiZWxvdyBwZXIgdHJpYWwqKiogICAKMy4gICIiIHNjYWxlZCAKNC4gIFNpbmdsZSBiZXRhIFNpbmdsZSBhbHBoYSByZWluZm9yY2VtZW50IGxlYXJuaW5nIG1vZGVsIChlc3RpbWF0ZSBib3RoIHRoZSBiZXRhIGFuZCB0aGUgYWxwaGEgKmkuZS4qIGxlYXJuaW5nIHJhdGUpCjUuICBTaW5nbGUgYmV0YSBzaW5nbGUgYWxwaGEgcmVpbmZvcmNlbWVudCBsZWFybmluZyB3aXRoIG1lYW4gKyBzZCBmb3IgdGhlIGJldGEgZXN0aW1hdGUgYXMgYSBwYXJhbWV0ZXIKNi4gIEJldGEgcGVyIHN0aW11bHVzICAgCjcuICBCZXRhIHBlciBzdGltdWx1cyArIGdlbmVyYWxpc2F0aW9uIHBhcmFtZXRlciAoVm1pbnVzID0gdm1pbnVzICsgd3ZwbHVzKSAgIAo4LiAgTGVha3kgYmV0YSAgIAo5LiAgTGVha3kgYmV0YSArIHVuY2VydGFpbnR5ICAgCjEwLiAgTGVha3kgYmV0YSArIHVuY2VydGFpbnR5ICsgYW54aWV0eSAgICAKCiMjIyBKdXN0aWZpY2F0aW9uIG9mIG1vZGVsIGNvbXBvbmVudHMKCipBbHBoYSoKTGVhcm5pbmcgcmF0ZSBwYXJhbWV0ZXIuIElmIGhpZ2ggdGhlbiB3aWxsIGJlIHZlcnkgaW5mbHVlbmNlZCBieSBwcmV2aW91cyB0cmlhbCBldmVudHMsIGlmIGxvdywgdGhlbiB3aWxsIGJlIG1vcmUgc3RhbmRhcmRseSBpbmZsdWVuY2VkIGJ5IGFjY3VtdWxhdGluZyBldmVudHMuCgoqIFNpbmdsZSBhbHBoYSBwZXIgcGVyc29uIAogICAgKiBBc3N1bWVzIHRoYXQgbGVhcm5pbmcgcmF0ZSBpcyBhIGNvbnN0YW50IGZvciBlYWNoIGluZGl2aWR1YWwgdGhhdCBtaWdodCBiZSBzY2FsZWQgYnkgb3RoZXIgZmFjdG9ycywgc3VjaCBhcyBjZXJ0YWludHkgb3Igc2Vuc2l0aXZpdHkuCgoqQmV0YXMqClZhcmlhbmNlL2NlcnRhaW50eSBwYXJhbWV0ZXIKCiogU2luZ2xlIGJldGEgcGVyIHBlcnNvbiAgIAogICAgKiAgIEFzc3VtZXMgdGhhdCB0aGUgZ2VuZXJhbCB2YXJpYW5jZSBhcm91bmQgcmF0aW5ncyBpcyB0aGUgc2FtZSByZWdhcmRsZXNzIG9mIHN0aW11bHVzLiBpLmUuIGFzIG11Y2ggdW5jZXJ0YWludHkgZm9yIENTKyBhc24gQ1MtCiogVHdvIGJldGEncyBwZXIgcGVyc29uCiAgICAqIEFzc3VtZXMgdGhhdCBjb25maWRlbmNlIC8gdW5jZXJ0YWludHkgbWlnaHQgZGlmZmVyIGJ5IHN0aW11bHVzLiBQcmVzdW1hYmx5IGFzIGEgZmFjdG9yIG9mIHJlaW5mb3JjZW1lbnQgcmF0ZS4KCgoKCiMgUHJlbGltaW5hcnkgey50YWJzZXR9CgojIyMgQ29tcGFyZSBhIHByaW9yaSB0byBkYXRhIHsudGFic2V0fQoKIyMjIyBTaW11bGF0ZSBkaWZmZXJlbnQgbGVhcm5pbmcgcmF0ZXMgey50YWJzZXR9Cgpvbmx5IGRvaW5nIHRoaXMgJ2FjY3VyYXRlbHknIGZvciB0aGUgYWNxdWlzaXRpb24gQ1MrLCBhcyB0aGUgc2ltdWxhdGlvbnMgcmVxdWlyZSBwcm9iYWJpbGl0eS4gSSBhbSB1c2luZyBjb250aW5nZW5jeSBmb3IgdGhpcyAoMC43NSkuIElmIHNldCBmb3IgMCBmb3IgYWxsIG90aGVyIHBoYXNlcyBhbmQgc3RpbXVsaSB0aGVuIGl0IGxvb2tzIGFzIGlmIHRoZSBsZWFybmluZyBzaG91bGQgYmUgZmxhdCByZWdhcmRsZXNzIG9mIGFscGhhLiBXZSBleHBlY3QgaW4gcmVhbGl0eSB0aGF0IHRoaXMgcHJvYmFiaWxpdHkgd2lsbCB2YXJ5IGJldHdlZW4gcGVvcGxlIGFuZCB3aWxsIGJlIHVubGlrZWx5IHRvIGJlIHplcm8uIFNvIHRlc3QgMTIgYW5kIDE4IHRyaWFscyB3aXRoIGEgcHJvYmFiaWxpdHkgb2YgMC41IGFuZCAwLjIgYXMgd2VsbC4KCiMjIyMjICAxMiB0cmlhbHM7IHByb2JhYmlsaXR5ID0gMC43NQoKYGBge3IgbGVhcXJuaW5nIHJhdGUgc2ltdWxhdGlvbnMsZWNobz1GfQoKI3RoaXMgaXMgYSB2ZXJ5IGJhc2ljIHNjcmlwdAojY3JlYXRlZCBieSBBbGV4IFBpa2UgMTQvMDIvMTkKI2l0IHNpbXVsYXRlcyB0aGUgbGVhcm5pbmcgb2YgdGhlIHZhbHVlIChRKSBvZiBhIHJld2FyZGVkIHN0aW11bHVzCiNhbHBoYSBpcyB0aGUgbGVhcm5pbmcgcmF0ZQojbnRyaWFscyBpcyB0aGUgbnVtYmVyIG9mIHRyaWFscyBpbiB0aGUgdGFzawojJ291dGNvbWVfcHJvYmFiaWxpc3RpYycgZ2VuZXJhdGVzIG91dGNvbWVzIHByb2JhYmlsaXN0aWNhbGx5IGZvciBudHJpYWxzCiMnb3V0Y29tZV9kZXRlcm1pbmlzdGljJyBhbHdheXMgaGFzIHRoZSBzYW1lIG91dGNvbWUgKDEpCgoKCiMjIGtscCBBQ1EgQ1NwIHNpbXMKCm5fdHJpYWxzID0gMTIKcHJvYmFiaWxpdHkgPSAwLjc1OyAjZWRpdCB0aGlzIHRvIGNoYW5nZSB0aGUgcHJvYmFiaWxpdHkgb2YgcmV3YXJkCgoja2xwIC0gbG9vcCB0aHJvdWdoIHNvbWUgZGlmZmVyZW50IGxlYXJuaW5nIHJhdGVzCgpwcmludCgiU2ltdWxhdGVkIGxlYXJuaW5nIHJhdGVzLiAxMiB0cmlhbHM7IHByb2JhYmlsaXR5ID0gMC43NSAoQ1NwIGFjcSBjb250aW5nZW5jeSkgXG4iKQoKZm9yIChhIGluIHNlcSgwOjAuOSxieT0wLjEpKSB7CiAgCiAgYWxwaGEgPC0gYSAgICNsZWFybmluZyByYXRlIChiZXR3ZWVuIDAgYW5kIDEpCiAgCm91dGNvbWVfZGV0ZXJtaW5pc3RpYyA9IHJlcCgxLG5fdHJpYWxzKQpvdXRjb21lX3Byb2JhYmlsaXN0aWMgPSBpZmVsc2UocnVuaWYoMTAwKTxwcm9iYWJpbGl0eSwxLDApCgpRPXJlcCgwLG5fdHJpYWxzKQpwYXIobWZyb3c9YygyLDEpKQpmb3IgKHQgaW4gMToobl90cmlhbHMtMSkpewogIFFbdCsxXT1RW3RdK2FscGhhKihvdXRjb21lX2RldGVybWluaXN0aWNbdF0gLSBRW3RdKTsKfQpwbG90KFEsdHlwZT0nbCcsY29sPSdibHVlJyx4bGFiPSd0cmlhbCBudW1iZXInKQp0aXRsZSgnRGV0ZXJtaW5pc3RpYycpCgpmb3IgKHQgaW4gMToobl90cmlhbHMtMSkpewogIFFbdCsxXT1RW3RdK2FscGhhKihvdXRjb21lX3Byb2JhYmlsaXN0aWNbdF0gLSBRW3RdKTsKfQoKCnBsb3QoUSx0eXBlPSdsJyxjb2w9J3JlZCcseGxhYj0ndHJpYWwgbnVtYmVyJykKdGl0bGUoJ1Byb2JhYmlsaXN0aWMnLHN1Yj1wYXN0ZTAoImFscGhhID0gIixhLHNlcD0iICIpKQoKfQoKCmBgYAojIyMjIyAgMTIgdHJpYWxzOyBwcm9iYWJpbGl0eSA9IDAuNQoKCmBgYHtyLGVjaG89Rn0KCgpuX3RyaWFscyA9IDEyCnByb2JhYmlsaXR5ID0gMC41OyAjZWRpdCB0aGlzIHRvIGNoYW5nZSB0aGUgcHJvYmFiaWxpdHkgb2YgcmV3YXJkCgoja2xwIC0gbG9vcCB0aHJvdWdoIHNvbWUgZGlmZmVyZW50IGxlYXJuaW5nIHJhdGVzCgpwcmludCgiU2ltdWxhdGVkIGxlYXJuaW5nIHJhdGVzLiAxMiB0cmlhbHM7IFByb2JhYmlsaXR5ID0gMC41XG4iKQoKZm9yIChhIGluIHNlcSgwOjAuOSxieT0wLjEpKSB7CiAgCiAgYWxwaGEgPC0gYSAgICNsZWFybmluZyByYXRlIChiZXR3ZWVuIDAgYW5kIDEpCiAgCm91dGNvbWVfZGV0ZXJtaW5pc3RpYyA9IHJlcCgxLG5fdHJpYWxzKQpvdXRjb21lX3Byb2JhYmlsaXN0aWMgPSBpZmVsc2UocnVuaWYoMTAwKTxwcm9iYWJpbGl0eSwxLDApCgpRPXJlcCgwLG5fdHJpYWxzKQpwYXIobWZyb3c9YygyLDEpKQpmb3IgKHQgaW4gMToobl90cmlhbHMtMSkpewogIFFbdCsxXT1RW3RdK2FscGhhKihvdXRjb21lX2RldGVybWluaXN0aWNbdF0gLSBRW3RdKTsKfQpwbG90KFEsdHlwZT0nbCcsY29sPSdibHVlJyx4bGFiPSd0cmlhbCBudW1iZXInKQp0aXRsZSgnRGV0ZXJtaW5pc3RpYycpCgpmb3IgKHQgaW4gMToobl90cmlhbHMtMSkpewogIFFbdCsxXT1RW3RdK2FscGhhKihvdXRjb21lX3Byb2JhYmlsaXN0aWNbdF0gLSBRW3RdKTsKfQoKCnBsb3QoUSx0eXBlPSdsJyxjb2w9J3JlZCcseGxhYj0ndHJpYWwgbnVtYmVyJykKdGl0bGUoJ1Byb2JhYmlsaXN0aWMnLHN1Yj1wYXN0ZTAoImFscGhhID0gIixhLHNlcD0iICIpKQoKfQoKYGBgCgojIyMjIyAgMTIgdHJpYWxzOyBwcm9iYWJpbGl0eSA9IDAuMgoKYGBge3IsZWNobz1GfQoKCm5fdHJpYWxzID0gMTIKcHJvYmFiaWxpdHkgPSAwLjI7ICNlZGl0IHRoaXMgdG8gY2hhbmdlIHRoZSBwcm9iYWJpbGl0eSBvZiByZXdhcmQKCiNrbHAgLSBsb29wIHRocm91Z2ggc29tZSBkaWZmZXJlbnQgbGVhcm5pbmcgcmF0ZXMKCnByaW50KCJTaW11bGF0ZWQgbGVhcm5pbmcgcmF0ZXMuIDEyIHRyaWFsczsgUHJvYmFiaWxpdHkgPSAwLjJcbiIpCgpmb3IgKGEgaW4gc2VxKDA6MC45LGJ5PTAuMSkpIHsKICAKICBhbHBoYSA8LSBhICAgI2xlYXJuaW5nIHJhdGUgKGJldHdlZW4gMCBhbmQgMSkKICAKb3V0Y29tZV9kZXRlcm1pbmlzdGljID0gcmVwKDEsbl90cmlhbHMpCm91dGNvbWVfcHJvYmFiaWxpc3RpYyA9IGlmZWxzZShydW5pZigxMDApPHByb2JhYmlsaXR5LDEsMCkKClE9cmVwKDAsbl90cmlhbHMpCnBhcihtZnJvdz1jKDIsMSkpCmZvciAodCBpbiAxOihuX3RyaWFscy0xKSl7CiAgUVt0KzFdPVFbdF0rYWxwaGEqKG91dGNvbWVfZGV0ZXJtaW5pc3RpY1t0XSAtIFFbdF0pOwp9CnBsb3QoUSx0eXBlPSdsJyxjb2w9J2JsdWUnLHhsYWI9J3RyaWFsIG51bWJlcicpCnRpdGxlKCdEZXRlcm1pbmlzdGljJykKCmZvciAodCBpbiAxOihuX3RyaWFscy0xKSl7CiAgUVt0KzFdPVFbdF0rYWxwaGEqKG91dGNvbWVfcHJvYmFiaWxpc3RpY1t0XSAtIFFbdF0pOwp9CgoKcGxvdChRLHR5cGU9J2wnLGNvbD0ncmVkJyx4bGFiPSd0cmlhbCBudW1iZXInKQp0aXRsZSgnUHJvYmFiaWxpc3RpYycsc3ViPXBhc3RlMCgiYWxwaGEgPSAiLGEsc2VwPSIgIikpCgp9CgpgYGAKCiMjIyMjICAxOCB0cmlhbHM7IHByb2JhYmlsaXR5ID0gMC41CgpgYGB7cixlY2hvPUZ9CgoKbl90cmlhbHMgPSAxOApwcm9iYWJpbGl0eSA9IDAuNTsgI2VkaXQgdGhpcyB0byBjaGFuZ2UgdGhlIHByb2JhYmlsaXR5IG9mIHJld2FyZAoKI2tscCAtIGxvb3AgdGhyb3VnaCBzb21lIGRpZmZlcmVudCBsZWFybmluZyByYXRlcwoKcHJpbnQoIlNpbXVsYXRlZCBsZWFybmluZyByYXRlcy4gMTggdHJpYWxzOyBQcm9iYWJpbGl0eSA9IDAuNVxuIikKCmZvciAoYSBpbiBzZXEoMDowLjksYnk9MC4xKSkgewogIAogIGFscGhhIDwtIGEgICAjbGVhcm5pbmcgcmF0ZSAoYmV0d2VlbiAwIGFuZCAxKQogIApvdXRjb21lX2RldGVybWluaXN0aWMgPSByZXAoMSxuX3RyaWFscykKb3V0Y29tZV9wcm9iYWJpbGlzdGljID0gaWZlbHNlKHJ1bmlmKDEwMCk8cHJvYmFiaWxpdHksMSwwKQoKUT1yZXAoMCxuX3RyaWFscykKcGFyKG1mcm93PWMoMiwxKSkKZm9yICh0IGluIDE6KG5fdHJpYWxzLTEpKXsKICBRW3QrMV09UVt0XSthbHBoYSoob3V0Y29tZV9kZXRlcm1pbmlzdGljW3RdIC0gUVt0XSk7Cn0KcGxvdChRLHR5cGU9J2wnLGNvbD0nYmx1ZScseGxhYj0ndHJpYWwgbnVtYmVyJykKdGl0bGUoJ0RldGVybWluaXN0aWMnKQoKZm9yICh0IGluIDE6KG5fdHJpYWxzLTEpKXsKICBRW3QrMV09UVt0XSthbHBoYSoob3V0Y29tZV9wcm9iYWJpbGlzdGljW3RdIC0gUVt0XSk7Cn0KCgpwbG90KFEsdHlwZT0nbCcsY29sPSdyZWQnLHhsYWI9J3RyaWFsIG51bWJlcicpCnRpdGxlKCdQcm9iYWJpbGlzdGljJyxzdWI9cGFzdGUwKCJhbHBoYSA9ICIsYSxzZXA9IiAiKSkKCn0KCmBgYAoKIyMjIyMgIDE4IHRyaWFsczsgcHJvYmFiaWxpdHkgPSAwLjIKCmBgYHtyLGVjaG89Rn0KCgpuX3RyaWFscyA9IDE4CnByb2JhYmlsaXR5ID0gMC4yOyAjZWRpdCB0aGlzIHRvIGNoYW5nZSB0aGUgcHJvYmFiaWxpdHkgb2YgcmV3YXJkCgoja2xwIC0gbG9vcCB0aHJvdWdoIHNvbWUgZGlmZmVyZW50IGxlYXJuaW5nIHJhdGVzCgpwcmludCgiU2ltdWxhdGVkIGxlYXJuaW5nIHJhdGVzLiAxOCB0cmlhbHM7IFByb2JhYmlsaXR5ID0gMC4yXG4iKQoKZm9yIChhIGluIHNlcSgwOjAuOSxieT0wLjEpKSB7CiAgCiAgYWxwaGEgPC0gYSAgICNsZWFybmluZyByYXRlIChiZXR3ZWVuIDAgYW5kIDEpCiAgCm91dGNvbWVfZGV0ZXJtaW5pc3RpYyA9IHJlcCgxLG5fdHJpYWxzKQpvdXRjb21lX3Byb2JhYmlsaXN0aWMgPSBpZmVsc2UocnVuaWYoMTAwKTxwcm9iYWJpbGl0eSwxLDApCgpRPXJlcCgwLG5fdHJpYWxzKQpwYXIobWZyb3c9YygyLDEpKQpmb3IgKHQgaW4gMToobl90cmlhbHMtMSkpewogIFFbdCsxXT1RW3RdK2FscGhhKihvdXRjb21lX2RldGVybWluaXN0aWNbdF0gLSBRW3RdKTsKfQpwbG90KFEsdHlwZT0nbCcsY29sPSdibHVlJyx4bGFiPSd0cmlhbCBudW1iZXInKQp0aXRsZSgnRGV0ZXJtaW5pc3RpYycpCgpmb3IgKHQgaW4gMToobl90cmlhbHMtMSkpewogIFFbdCsxXT1RW3RdK2FscGhhKihvdXRjb21lX3Byb2JhYmlsaXN0aWNbdF0gLSBRW3RdKTsKfQoKCnBsb3QoUSx0eXBlPSdsJyxjb2w9J3JlZCcseGxhYj0ndHJpYWwgbnVtYmVyJykKdGl0bGUoJ1Byb2JhYmlsaXN0aWMnLHN1Yj1wYXN0ZTAoImFscGhhID0gIixhLHNlcD0iICIpKQoKfQoKYGBgCgoKIyMjIyBQbG90IHN1YnNldCBvZiB0cmFqZWN0b3JpZXMgaW4gZmxhcmUKCmBgYHtyIHN1YnNldCBGTEFSZSBkYXRhLGVjaG89Rn0KCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KGRwbHlyKQoKc2F2ZSA8LSAiL1VzZXJzL2tpcnN0aW4vRHJvcGJveC9TR0RQL0ZMQVJlL0ZMQVJlX01BU1RFUi9Qcm9qZWN0cy9MYXRlbnRHcm93dGgvRmlndXJlcy8iCmRhdCA8LSBmcmVhZCgiL1VzZXJzL2tpcnN0aW4vRHJvcGJveC9TR0RQL0ZMQVJlL0ZMQVJlX01BU1RFUi9Qcm9qZWN0cy9MYXRlbnRHcm93dGgvRGF0YXNldHMvRkNfdDFfbXBsdXNfZGF0YS5jc3YiLGRhdGEudGFibGUgPSBGKQoKIyMgcmFuZG9tbHkgc2VsZWN0IDEwIGluZGl2aWR1YWxzLgoKc2V0LnNlZWQoMjAxNikKZmlsZSA8LSBzYW1wbGVfbihkYXQsMTApCgoKYXAgPC0gc3Vic2V0KGZpbGUsc2VsZWN0PWMoIlN1YmplY3RfSUQiLCJGQ1QxXzFleHBDU3BfMSIsIAogICAgICAgICAgICAgIkZDVDFfMWV4cENTcF8yIiwgIkZDVDFfMWV4cENTcF8zIiwgIkZDVDFfMWV4cENTcF80IiwgIkZDVDFfMWV4cENTcF81IiwgCiAgICAgICAgICAgICAiRkNUMV8xZXhwQ1NwXzYiLCAiRkNUMV8xZXhwQ1NwXzciLCAiRkNUMV8xZXhwQ1NwXzgiLCAiRkNUMV8xZXhwQ1NwXzkiLCAKICAgICAgICAgICAgICJGQ1QxXzFleHBDU3BfMTAiLCAiRkNUMV8xZXhwQ1NwXzExIiwgIkZDVDFfMWV4cENTcF8xMiIpKQoKYW0gPC0gc3Vic2V0KGZpbGUsc2VsZWN0PWMoIlN1YmplY3RfSUQiLCJGQ1QxXzFleHBDU21fMSIsIAogICAgICAgICAgICAgIkZDVDFfMWV4cENTbV8yIiwgIkZDVDFfMWV4cENTbV8zIiwgIkZDVDFfMWV4cENTbV80IiwgIkZDVDFfMWV4cENTbV81IiwgCiAgICAgICAgICAgICAiRkNUMV8xZXhwQ1NtXzYiLCAiRkNUMV8xZXhwQ1NtXzciLCAiRkNUMV8xZXhwQ1NtXzgiLCAiRkNUMV8xZXhwQ1NtXzkiLCAKICAgICAgICAgICAgICJGQ1QxXzFleHBDU21fMTAiLCAiRkNUMV8xZXhwQ1NtXzExIiwgIkZDVDFfMWV4cENTbV8xMiIpKQoKZXAgPC0gc3Vic2V0KGZpbGUsc2VsZWN0PWMoIlN1YmplY3RfSUQiLCJGQ1QxXzNleHBDU3BfMSIsICJGQ1QxXzNleHBDU3BfMiIsICJGQ1QxXzNleHBDU3BfMyIsIAogICAgICAgICAgICAgIkZDVDFfM2V4cENTcF80IiwgIkZDVDFfM2V4cENTcF81IiwgIkZDVDFfM2V4cENTcF82IiwgIkZDVDFfM2V4cENTcF83IiwgCiAgICAgICAgICAgICAiRkNUMV8zZXhwQ1NwXzgiLCAiRkNUMV8zZXhwQ1NwXzkiLCAiRkNUMV8zZXhwQ1NwXzEwIiwgIkZDVDFfM2V4cENTcF8xMSIsIAogICAgICAgICAgICAgIkZDVDFfM2V4cENTcF8xMiIsICJGQ1QxXzNleHBDU3BfMTMiLCAiRkNUMV8zZXhwQ1NwXzE0IiwgIkZDVDFfM2V4cENTcF8xNSIsIAogICAgICAgICAgICAgIkZDVDFfM2V4cENTcF8xNiIsICJGQ1QxXzNleHBDU3BfMTciLCAiRkNUMV8zZXhwQ1NwXzE4IikpCgplbSA8LSBzdWJzZXQoZmlsZSxzZWxlY3Q9YygiU3ViamVjdF9JRCIsIkZDVDFfM2V4cENTbV8xIiwgCiAgICAgICAgICAgICAiRkNUMV8zZXhwQ1NtXzIiLCAiRkNUMV8zZXhwQ1NtXzMiLCAiRkNUMV8zZXhwQ1NtXzQiLCAiRkNUMV8zZXhwQ1NtXzUiLCAKICAgICAgICAgICAgICJGQ1QxXzNleHBDU21fNiIsICJGQ1QxXzNleHBDU21fNyIsICJGQ1QxXzNleHBDU21fOCIsICJGQ1QxXzNleHBDU21fOSIsIAogICAgICAgICAgICAgIkZDVDFfM2V4cENTbV8xMCIsICJGQ1QxXzNleHBDU21fMTEiLCAiRkNUMV8zZXhwQ1NtXzEyIiwgIkZDVDFfM2V4cENTbV8xMyIsIAogICAgICAgICAgICAgIkZDVDFfM2V4cENTbV8xNCIsICJGQ1QxXzNleHBDU21fMTUiLCAiRkNUMV8zZXhwQ1NtXzE2IiwgIkZDVDFfM2V4cENTbV8xNyIsIAogICAgICAgICAgICAgIkZDVDFfM2V4cENTbV8xOCIpKQoKCgojIyBtZWx0IHRvIGxvbmdmb3JtCgphcG10IDwtIG1lbHQoYXAsCiAgICAgICAgICAgaWQudmFyPSJTdWJqZWN0X0lEIikKYXBtdCA8LSBhcG10WyhvcmRlcihhcG10JFN1YmplY3RfSUQpKSxdCmFwbXQkVHJpYWwgPC0gcmVwKDE6MTIpCgphbW10IDwtIG1lbHQoYW0sCiAgICAgICAgICAgaWQudmFyPSJTdWJqZWN0X0lEIikKYW1tdCA8LSBhbW10WyhvcmRlcihhbW10JFN1YmplY3RfSUQpKSxdCmFtbXQkVHJpYWwgPC0gcmVwKDE6MTIpCgplcG10IDwtIG1lbHQoZXAsCiAgICAgICAgICAgaWQudmFyPSJTdWJqZWN0X0lEIikKZXBtdCA8LSBlcG10WyhvcmRlcihlcG10JFN1YmplY3RfSUQpKSxdCmVwbXQkVHJpYWwgPC0gcmVwKDE6MTgpCgplbW10IDwtIG1lbHQoZW0sCiAgICAgICAgICAgaWQudmFyPSJTdWJqZWN0X0lEIikKZW1tdCA8LSBlbW10WyhvcmRlcihlbW10JFN1YmplY3RfSUQpKSxdCmVtbXQkVHJpYWwgPC0gcmVwKDE6MTgpCgojIyBwbG90IGxpbmVzIGFuZCBib3ggcGxvdHMgZm9yIHRoZSBzdWJzZXQKCiMgYWNxIENTKwphY3AgPC0gZ2dwbG90KGFwbXQsCiAgICAgICAgICAgICAgYWVzKFRyaWFsLCB2YWx1ZSkpICAgICAgICAgICAgKwogIGdlb21fYm94cGxvdChhZXMoZ3JvdXA9dmFyaWFibGUpKSAgICAgICAgICsKICAgIGdlb21fbGluZShhZXMoZ3JvdXAgPSBTdWJqZWN0X0lELAogICAgICAgICAgICAgICAgICBjb2xvcj1TdWJqZWN0X0lEKSkgICAgICAgICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzPXJhaW5ib3coMTApKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSAgICAgICAgICAgKwogIGdndGl0bGUoIkNTKyBhY3F1aXNpdGlvbiIpCgojIGFjcSBDUy0KYWNtIDwtIGdncGxvdChhbW10LAogICAgICAgICAgICAgIGFlcyhUcmlhbCwgdmFsdWUpKSAgICAgICAgICAgICsKICBnZW9tX2JveHBsb3QoYWVzKGdyb3VwPXZhcmlhYmxlKSkgICAgICAgICArCiAgICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gU3ViamVjdF9JRCwKICAgICAgICAgICAgICAgICAgY29sb3I9U3ViamVjdF9JRCkpICAgICAgICArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycz1yYWluYm93KDEwKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgICAgICAgICAgICsKICBnZ3RpdGxlKCJDUy0gYWNxdWlzaXRpb24iKQoKCiMgRXh0IENTKwpleHAgPC0gZ2dwbG90KGVwbXQsCiAgICAgICAgICAgICAgYWVzKFRyaWFsLCB2YWx1ZSkpICAgICAgICAgICAgKwogIGdlb21fYm94cGxvdChhZXMoZ3JvdXA9dmFyaWFibGUpKSAgICAgICAgICsKICAgIGdlb21fbGluZShhZXMoZ3JvdXAgPSBTdWJqZWN0X0lELAogICAgICAgICAgICAgICAgICBjb2xvcj1TdWJqZWN0X0lEKSkgICAgICAgICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzPXJhaW5ib3coMTApKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSAgICAgICAgICAgKwogIGdndGl0bGUoIkNTKyBFeHRpbmN0aW9uIikKCiMgRXh0IENTLQpleG0gPC0gZ2dwbG90KGVtbXQsCiAgICAgICAgICAgICAgYWVzKFRyaWFsLCB2YWx1ZSkpICAgICAgICAgICAgKwogIGdlb21fYm94cGxvdChhZXMoZ3JvdXA9dmFyaWFibGUpKSAgICAgICAgICsKICAgIGdlb21fbGluZShhZXMoZ3JvdXAgPSBTdWJqZWN0X0lELAogICAgICAgICAgICAgICAgICBjb2xvcj1TdWJqZWN0X0lEKSkgICAgICAgICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzPXJhaW5ib3coMTApKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSAgICAgICAgICAgKwogIGdndGl0bGUoIkNTLSBFeHRpbmN0aW9uIikKCmFjcAphY20KZXhwCmV4bQpgYGAKCgojIyMgVHJ5IFJTdGFuCgpTZWUgaWYgdGhlIGJhc2ljIHB1bmlzaG1lbnQgb25seSBsZWFybmluZyBtb2RlbCBmb3IgdGhlIENTKyBhbmQgQ1MtIHdvcmtzIHdpdGggdGhlIEZMQVJlIG1hc3RlciBkYXRhCgojIyMjIFJ1biB0aGUgOHNjaG9vbHMgY2hlY2sKCkZyb20gdGhlIFtyc3RhbiBnaXRodWJdKGh0dHBzOi8vZ2l0aHViLmNvbS9zdGFuLWRldi9yc3Rhbi93aWtpL1JTdGFuLUdldHRpbmctU3RhcnRlZCkKClRoaXMgaXMgdG8gY2hlY2sgdGhhdCBhbGwgaXMgY29tcGlsaW5nIGFuZCB3b3JraW5nIGFuZCB0byBnaXZlIGFuZCBpZGVhIG9mIGRhdGEgZm9ybWF0IGV0Yy4KCgoKIyMjIyBTZXQgdXAgcHJvY2VkdXJlIHRvIGNyZWF0ZSBhbmQgc3luYyBtb2RlbHMuCgpUaGlzIGRpcmVjdHMgdG8gbXkgbG9jYWwgbWFjaGluZSBoZXJlICoqKi9Vc2Vycy9raXJzdGluL0Ryb3Bib3gvU0dEUC9GTEFSZS9GTEFSZV9NQVNURVIvUHJvamVjdHMvSGllcmFjaGFsX21vZGVsbGluZy9TY3JpcHRzKioqIGFuZCBpcyByZW1vdGVseSBsaW5rZWQgdG8gdGhlIGdpdGh1YiBbcmVwb3NpdG9yeSBoZXJlXShodHRwczovL2dpdGh1Yi5jb20va2xwdXJ2ZXMvRkxBUmVfQmF5ZXNpYW5faGllcmFyY2hpY2FsKS4gIAoKIyMjIyMgTWFrZSBzdXJlIHRoZSBtb3N0IHVwIHRvIGRhdGUgc3RhbiBmaWxlIGlzIGluIHRoZSByZW1vdGUgcmVwbwoKCmBgYHtiYXNoIHVwZGF0ZSBmcm9tIGdpdH0KCmdpdCBwdWxsIEJheWVzX21vZGVsbGluZwogICAKYGBgCgoKCiMgQW5hbHlzZXMKCiMjIyBGdW5jdGlvbiBibG9jawoKCmBgYHtyIGNhbGwgbGlicmFyaWVzLCBlY2hvPUYscmVzdWx0cz1GfQoKI3JtKGxpc3Q9bHMoKSkKCmxpYnJhcnkodGliYmxlKQpsaWJyYXJ5KHBzeWNoKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKCgojIGRpcmVjdG9yaWVzCndvcmtpbmdkaXI9Jy9Vc2Vycy9raXJzdGluL0Ryb3Bib3gvU0dEUC9GTEFSZS9GTEFSZV9NQVNURVIvUHJvamVjdHMvSGllcmFjaGFsX21vZGVsbGluZy9Nb2RlbGxpbmcnCnNjcmlwdGRpcj0nL1VzZXJzL2tpcnN0aW4vRHJvcGJveC9TR0RQL0ZMQVJlL0ZMQVJlX01BU1RFUi9Qcm9qZWN0cy9IaWVyYWNoYWxfbW9kZWxsaW5nL1NjcmlwdHMnCmRhdGFkaXI9Jy9Vc2Vycy9raXJzdGluL0Ryb3Bib3gvU0dEUC9GTEFSZS9GTEFSZV9NQVNURVIvUHJvamVjdHMvTGF0ZW50R3Jvd3RoL0RhdGFzZXRzLycKCiMjIHdyaXRlIGZ1bmN0aW9uIHRvIHNldCBlYWNoIGJsb2NrIGFzIHRlc3Qgb3Igbm90IGluZGl2aWR1YWxseS4KIyMgdGhyZWUgdGVzdGluZyBsZXZlbHMgLSBtaW4sIG1lZCwgbWF4LiAKIyMgaWYgb2ZmLCB0aGVuIHdpbGwgc2V0IHRvIG5vcm1hbCBzdGFuIHBhcmFtZXRlciBvZiAxMDAwIHdhcm11cCBhbmQgNDAwMCBpdGVyYXRpb25zIG9uIDQgY2hhaW5zCgoKYGBgCgoKIyMjIyB0ZXN0IGZ1bmN0aW9uCgpBIGZ1bmN0aW9uIGZvciBydW5uaW5nIG1pbmltYWwsIG1lZGl1bSBvciBtYXhpbWFsIHRlc3RzIG9mIHRoZSBzdGFuIGRhdGEuIFRoaXMgY2hhbmdlcyBob3cgbWFueSBjaGFpbnMgYW5kIGl0ZXJhdGlvbnMgYXJlIHJ1biAKCmBgYHtyIHRlc3Rpbmcgc3Rhbn0KdGVzdGluZyA8LSBmdW5jdGlvbih4KSB7CiAgCiAgaWYgKHggJWluJSBjKCdtaW4nLCJNaW4iKSkgewogICAgY2hhaW5faXRlcjw8LTQwMAogICAgd2FybV91cDw8LTEwMAogICAgY2hhaW5fbjw8LTEKICB9IGVsc2UgaWYgKCB4ICVpbiUgYygnbWVkJyAsJ01lZCcpKSB7CiAgICAKICAgIGNoYWluX2l0ZXI8PC0xMDAwCiAgICB3YXJtX3VwPDwtNTAwCiAgICBjaGFpbl9uPDwtMQogICAgCiAgfSBlbHNlIGlmICggeCAlaW4lIGMoJ21heCcsJ01heCcpKSB7CiAgICAKICAgIGNoYWluX2l0ZXI8PC0yMDAwCiAgICB3YXJtX3VwPDwtMTAwMAogICAgY2hhaW5fbjw8LTIKICAgIAogIH0gZWxzZSBpZiAoIHggJWluJSBjKCdmdWxsJyAsJ0Z1bGwnKSkgewogICAgCiAgICBjaGFpbl9pdGVyPDwtNDAwMAogICAgd2FybV91cDw8LTEwMDAKICAgIGNoYWluX248PC00CiAgICAKICB9IGVsc2UgaWYgKCB4ICVpbiUgYygnc2tpcCcgLCdTa2lwJykpIHsKICAgIAogICAgY2hhaW5faXRlcjw8LTAKICAgIHdhcm1fdXA8PC0wCiAgICBjaGFpbl9uPDwtMAogICAgCiAgfSAKCn0KYGBgCgojIyMjIE1vZGVsIHJ1biwgbG9hZCBvciBza2lwCgoKQSBmdW5jdGlvbiBmb3IgZWl0aGVyIHJ1bm5pbmcgdGhlIG1vZGVsLCBsb2FkaW5nIGluIHRoZSBkYXRhIGlmIGl0IGFscmVhZHkgZXhpc3RzIGFuZCBkb2VzbnQgbmVlZCByZWRvaW5nLCBvciBza2lwcGluZyBibG9jayBlbnRpcmVseS4KCnggaXMgdGVzdGluZyBjb21tYW5kLCBza2lwIG9yIGxvYWQgY29tbWFucwp5IGlzIHN0YW4gc2NyaXB0CnogaXMgZmxhcmVfZGF0YSBzZXQgdG8gdXNlLgoKKk5vdGUgdGhhdCB0aGlzIG5lZWRzIHRvIGhhdmUgc2NyaXB0ZGlyIGFuZCBkYXRhZGlyIGV4aXN0aW5nIGluIHRoZSB3b3JrcGxhY2UqCgpgYGB7ciBydW4gb3IgbG9hZH0KCm1vZGVsX3J1biA8LSBmdW5jdGlvbih4LHkseikgewoKICBpZiAoeCAlaW4lIGMoJ3NraXAnLCJTa2lwIikpIHsKICAgIAogICAgc3RvcCgic2tpcHBpbmcgdGhpcyBtb2RlbCIpCiAgICAKICB9CiAgICAKICBpZiAoeCAlaW4lIGMoJ21pbicsIm1lZCIsIm1heCIsIk1pbiIsIk1lZCIsIk1heCIsImZ1bGwiLCJGdWxsIikpIHsKICAgIAogIHByaW50KCJydW5uaW5nIG1vZGVsIikKICAKICB0ZXN0aW5nKHgpCiAgc3Rhbm5hbWUgPSB5CiAgc3RhbmZpbGUgPC0gZmlsZS5wYXRoKHNjcmlwdGRpciwgc3Rhbm5hbWUpCiAgZmxhcmVfZGF0YSA8LSB6CiAgIyBub3RlIHRoYXQgZmxhcmVfZGF0YSBpcyBzZXQgdXAgZWxzZXdoZXJlIChzZWUgYmxvY2sgYmVsb3cpCiAgZmxhcmVfZml0IDwtIHN0YW4oZmlsZSA9IHN0YW5maWxlLCBkYXRhID0gZmxhcmVfZGF0YSwgaXRlcj1jaGFpbl9pdGVyLCBjaGFpbnMgPSBjaGFpbl9uKSAjYWRkIHdvcmtpbmcgZGlyPwogIHNhdmVfbmFtZSA8LSBnc3ViKCIuc3RhbiIsIi5yZHMiLCBzdGFubmFtZSkKICBzYXZlUkRTKGZsYXJlX2ZpdCwgZmlsZT1maWxlLnBhdGgoZGF0YWRpcixzYXZlX25hbWUpKQogIAogIHByaW50KHRyYWNlcGxvdChmbGFyZV9maXQsJ2xwX18nKSkKICAKICAjIGV4dHJhY3QgZml0IGRhdGEKICByZXR1cm4oc3VtbWFyeShmbGFyZV9maXQpKQogIAogIH0gCiAgCiAgaWYgKHggJWluJSBjKCdsb2FkJywiTG9hZCIpKSB7CiAgICAKICAgIHByaW50KCJMb2FkaW5nIGV4aXN0aW5nIG1vZGVsIGZpdCBkYXRhIikKICAgIHN0YW5uYW1lID0gZ3N1YigiLnN0YW4iLCIucmRzIiwgeSkKICAgIGZpdGZpbGUgPC0gcmVhZFJEUyhmaWxlPXBhc3RlMChkYXRhZGlyLHN0YW5uYW1lKSkKICAgIHByaW50KHRyYWNlcGxvdChmaXRmaWxlLCdscF9fJykpCiAgICByZXR1cm4oc3VtbWFyeShmaXRmaWxlKSkKICAgIAogICAgCiAgICAKICB9Cn0KCmBgYAoKIyMjIyBvdXQgZGVzY3JpYmUKCgpGdW5jdGlvbiBmb3IgZGVzY3JpYmluZyB0aGUgbWVhbiBldGMgb2YgZnJlZWx5IGVzdGltYXRlZCBwYXJhbWV0ZXJzIGZyb20gU1RBTiBvdXRwdXQKCmBgYHtyIHN0YW4gb3V0IGRlc2NyaXB0aXZlc30KCm91dF9kZXNjcmliZTwtIGZ1bmN0aW9uKHN1bW1hcnksbixhbGwgPSBOVUxMKXsKICAKbGlicmFyeShkcGx5cikKCiAgcHJpbnQocGFzdGUwKGNoYWluX2l0ZXIsICIgaXRlcmF0aW9ucyAiLCAnIG9uICcsIGNoYWluX24sJyBjaGFpbnMuJyxzZXA9IiAiKSkKCiAgcHJpbnQocGFzdGUoIkVzdGltYXRlZCIsKGRpbShzdW1tYXJ5JHN1bW1hcnkpWzFdLTEpIC8gbnN1YiwiRnJlZSBwYXJhbWF0ZXJzIHBlciBwZXJzb24iLHNlcD0iICIpKQoKICBzdW1tYXJ5IDwtIGRhdGEuZnJhbWUoc3VtbWFyeSRzdW1tYXJ5WygxOihkaW0oc3VtbWFyeSRzdW1tYXJ5KS0xKVsxXSksXSkKCnRhYmxlIDwtIHN1bW1hcnkgJT4lCiAgbXV0YXRlKHBhcmFtZXRlciA9IHJlcCgxOihkaW0oc3VtbWFyeSlbMV0vbiksZWFjaCA9IG4gKSkgJT4lCiAgZ3JvdXBfYnkocGFyYW1ldGVyKSAlPiUKICBzdW1tYXJpemUobWVhbiA9IG1lYW4obWVhbixuYS5ybT1UKSwgCiAgICAgICAgICAgIHNlX21lYW4gPSBtZWFuKHNlX21lYW4sbmEucm09KSwgCiAgICAgICAgICAgIHNkID0gbWVhbihzZCxuYS5ybT1UKSwKICAgICAgICAgICAgUmhhdCA9IG1lYW4oUmhhdCxuYS5ybT1UKSkKCnBhcmFtX25hbWVzIDwtIHJvdy5uYW1lcyhzdW1tYXJ5KVsoc2VxKDEsZGltKHN1bW1hcnkpWzFdLG4pKV0KCnRhYmxlJHBhcmFtZXRlciA8LSBwYXJhbV9uYW1lcwoKaWYgKGlzLm51bGwoYWxsKSAmIGRpbSh0YWJsZSlbMV0gPiAxMCkgewogIAogIHByaW50KCJUaGlzIHRhYmxlIGlzIHZlcnkgbGFyZ2UuIFJldHVybmluZyBvbmx5IHRoZSB0b3AgNiBlbnRyaWVzIHVubGVzcyB5b3UgaGF2ZSBzZXQgdGhlIDNyZCBmdW5jdGlvbiBvcHRpb24gdG8gJ2FsbCcuICIpCiAgcmV0dXJuKGhlYWQodGFibGUpKQogIAp9IGVsc2UgewogIAogIHJldHVybih0YWJsZSkKfQoKfQoKCmBgYAoKIyMjIyBCSUMKCkNhbm9uaW5jYWwgQklDIGZ1bmN0aW9uIGZyb20gbG9nIGxpa2VsaWhvb2QgY291cnRlc3kgb2YgQWxleCBQaWtlCgpgYGB7ciBjYW5vbmljYWwgQklDfQojIyBjYW5vbmljYWwgQklDIGZ1bmN0aW9uIChBbGV4IFBpa2VzKQoKYmljPC1mdW5jdGlvbih0cmlhbHMsbmVnX2xvZ19saWtlLG5wYXJhbSkgewogIGlmIChzdW0obmVnX2xvZ19saWtlPDApPjApe3ByaW50KCdjaGVjayB0aGlzIGlzIG5lZ2F0aXZlIGxvZyBsaWtlbGlob29kISEnKX0gCiAgMipuZWdfbG9nX2xpa2UrbnBhcmFtKmxvZyh0cmlhbHMpICNjYW5vbmljYWwKfQoKCmBgYAoKCiMjIyMgbW9kZWwgcGxvdAoKYSBmdW5jdGlvbiBmb3IgcGxvdHRpbmcgQklDIGJhcmNoYXJ0IGZvciBkaWZmZXJlbnQgbW9kZWxzIGNvbnRhaW5lZCBpbiBhIGRhdGFzZXQKCmBgYHtyIGNvbXBhcmUgbW9kZWxzfQojIyBtb2RlbCBjb21wYXJlIHBsb3QgZnVuY3Rpb24KCnBsb3RfbW9kZWxzIDwtIGZ1bmN0aW9uKGRhdGFzZXQpIHsKICAKZGF0YXNldCRCSUMgPC0gb2RwKGFzLm51bWVyaWMoZGF0YXNldCRCSUMpKQoKZGF0YXNldCA8LSBhcy5kYXRhLmZyYW1lKG5hLm9taXQoZGF0YXNldCkpCgp5bWludiA8LSBtaW4oZGF0YXNldCRCSUMsbmEucm09VCkgLTUKeW1heHYgPC0gbWF4KGRhdGFzZXQkQklDLG5hLnJtPVQpICs1CgpwbG90IDwtIGdncGxvdChkYXRhc2V0LGFlcyh4PXJlb3JkZXIobW9kZWwsQklDKSx5PUJJQykpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnModGl0bGUgPSAiTW9kZWwgY29tcGFyaXNvbiIsCiAgICAgICB5PSJCYXllc2lhbiBJbmZvcm1hdGlvbiBDcml0ZXJpb24gKEJJQykiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cz1jKHltaW52LHltYXh2KSxvb2I9cmVzY2FsZV9ub25lKQoKc2hvdyhwbG90KQoKfQoKCgoKYGBgCgoKIyMjIyBPRFAKdGhlIGJlbG93IGlzIGEgZnVuY3Rpb24gdGhhdCB3aWxsIGZvcm1hdCB5b3VyIG51bWJlcnMgdG8gb25lIGRlY2ltYWwgcGxhY2UgdXNpbmcgc3ByaW50ZgoKYGBge3Igb25lIGRlY2ltYWwgcGxhY2UgZnVuY3Rpb259CgpvZHAgPC0gZnVuY3Rpb24oeCkgewogIGFzLm51bWVyaWMoc3ByaW50ZigiJTIuMmYiLHgpKQp9CgpgYGAKCgoKIyMgQ3JlYXRlIGRhdGFzZXRzCgojIyMgbm90ZXMKCldlIG5lZWQgdG8gcmVzY2FsZSBvdXIgZGF0YXNldCBoZXJlIHRvIGJlIGJldHdlZW4gMCBhbmQgMS4gCgpJbXBvcnRhbnRseSwgYmVjYXVzZSB3ZSBhcmUgdXNpbmcgdGhlIHByb3BvcnRpb24gb2YgdHJpYWxzIHRoYXQgKiphcmUgbm90KiogcmVpbmZvcmNlZCBhcyBhIGtub3duIHBhcmFtZXRlciBmb3Igc3RhdGlzdGljYWwgcmVhc29ucyAod2UgZG9uJ3Qgd2FudCBhIHByb3BvcnRpb24gb2YgLjc1IGFuZCAxLCBiZXR0ZXIgdG8gaGF2ZSAuMjUgYW5kIDApLCB3ZSBoYXZlIG1hZGUgb3VyIHJlc2NhbGVkIGV4cGVjdGFuY3kgdmFsdWVzIGFzIDEgLSByZXNjYWxlZCh4KS4gVGhpcyBtZWFucyB0aGF0IHdlIHdpbGwgc3RpbGwgYmUgYWJsZSB0byBpbnRlcnByZXQgdGhlIHJlc3VsdHMgaW4gdGhlIGV4cGVjdGVkIHdheSAoaS5lLiBoaWdoZXIgcmF0aW5nIGlzIGdyZWF0ZXIgZXhwZWN0YXRpb24gb2YgdGhlIG91dGNvbWUpLgoKCiMjIyBFeHBlY3RhbmN5IGRhdGEKCmxvYWQgaW4gdGhlIHdlZWsgMSBhcHAgYW5kIGxhYiBkYXRhIGZvciBGTEFSZSBwaWxvdCwgVFJUIGFuZCBoZWFkcGhvbmVzIHN0dWRpZXMuIE1ha2UgaXQgbG9uZyBmb3JtLgoKVHJ5IHdpdGggYWNxdWlzaXRpb24gZGF0YSBmaXJzdC4gVGhpcyBpcyBmb3JtYXR0ZWQgd2l0aCBubyBjb2x1bW4gbmFtZXMsIHdpdGggbm8gbWlzc2luZyBkYXRhLgoKRGVyaXZldGhlIG4gcGFyYW1ldGVyIGZvciBib3RoIGZpbGVzIGFuZCBjaGVjayB0aGVzZSBtYXRjaAoKCiMjIyMgc2V0IHVwIHRyaWFsIG51bWJlcgoKYGBge3IgdHJpYWwgbnVtYmVyfQojIGNyZWF0ZSB0aGUgbiB0cmlhbHMgdmFyaWFibGUgZm9yIFJTdGFuCm50cmlhbHM9MTIKYGBgCgoKCmBgYHtyfQoKc3Rhbm5hbWU9J3B1bmlzaF9vbmx5LnN0YW4nCm1pbnVzX25hbWUgPC0gJ2JheWVzX2FjcV9taW51cy5jc3YnCnBsdXNfbmFtZSA8LSAiYmF5ZXNfYWNxX3BsdXMuY3N2IgoKc3RhbmZpbGUgPC0gZmlsZS5wYXRoKHNjcmlwdGRpciwgc3Rhbm5hbWUpCm1pbnVzZmlsZSA8LSBmaWxlLnBhdGgoZGF0YWRpcixtaW51c19uYW1lKQpwbHVzZmlsZSA8LSBmaWxlLnBhdGgoZGF0YWRpcixwbHVzX25hbWUpCgoKbWludXMgPC0gZnJlYWQobWludXNmaWxlLGRhdGEudGFibGU9RikKcGx1cyA8LWZyZWFkKHBsdXNmaWxlLGRhdGEudGFibGU9RikKCm5hY3FtIDwtIGRpbShtaW51cylbMV0KbmFjcXAgPC0gZGltKHBsdXMpWzFdCgoKIyMgY2hlY2sgdGhhdCB0aGVzZSBtYXRjaCBhbmQgY3JlYXRlIG5zdWIgdmFyaWFibGUgZm9yIFJTdGFuCgppZiAobmFjcW0gPT0gbmFjcXApIHsKICBwcmludCgnc3ViamVjdCBudW1iZXIgbWF0Y2gnKQogIG5zdWIgPC0gbmFjcW0KICAKICBwcmludChwYXN0ZSgnbnN1YiBzZXQgdG8nLG5zdWIsc2VwPSIgIikpCn0gZWxzZSB7CiAgcHJpbnQoJ1dBUk5JTkc6IHN1YmplY3QgbnVtYmVyIGRvZXMgbm90IG1hdGNoLiBDaGVjayBtYXN0ZXIgZGF0YXNldCcpCn0KCiMgY2hlY2sgdGhlIGZpbGUgZm9ybWF0IGlzIG9rCgptaW51c1sxOjIsXQpwbHVzWzE6MixdCgoKCmBgYAoKVGhlIGV4cGVjdGFuY3kgcmF0aW5nIGRhdGFzZXRzIGxvb2sgbGlrZSB0aGV5IGFyZSBmb3JtYXR0ZWQgZmluZSBhbmQgbnRyaWFscyBhbmQgbnN1YiB2YXJpYWJsZXMgc2hvdWxkIGV4aXN0LiAKCiMjIyMgbWFrZSByYXRpbmcgZGF0YSBiaW5hcnkKCgpmb3Igbm93IHRvIHNlZSBpZiBzdGFuIHJ1bnMgdXNpbmcgYmVybm91bGxpLWxvZ2l0IGZ1bmN0aW9uIG1ha2UgYmluYXJ5IHJlc3Bvc25lcyBmcm9tIGV4cGVjdGFuY3kgaS5lLiA+PTQuNSA9PTEsIDw9IDQuNSA9PTAuIAoKCgpgYGB7cn0KCmJpbmFyaXNlIDwtIGZ1bmN0aW9uKHgpIHsKICBpZmVsc2UoeCA+PSA0LjUsMSwwKQp9CgpgYGAKCmBgYHtyfQoKCm1pbnVzYiA8LSBkYXRhLmZyYW1lKGFwcGx5KG1pbnVzLDIsZnVuY3Rpb24oeCkgYmluYXJpc2UoeCkpKQoKcGx1c2IgPC0gZGF0YS5mcmFtZShhcHBseShwbHVzLDIsZnVuY3Rpb24oeCkgYmluYXJpc2UoeCkpKQoKYGBgCgoKIyMjIFByb3BvcnRpb24gc2NyZWFtcyBkYXRhCgpUaGlzIGlzIGEgdmVjdG9yIGNvbnRhaW5pbmcgdGhlIGFic29sdXRlIG51bWJlciBvZiB0cmlhbHMgd2hlcmUgbm8gc2NyZWFtIG9jY3VycmVkIGZvciBlYWNoIHN0aW11bHVzLiBBcyB0aGVyZSB3YXMgYSA3NSUgcmVpbmZvcmNlbWVudCByYXRlIGZvciB0aGUgQ1MrICg5LzEyIHRyaWFscyksIHRoaXMgaXMgYSB2ZWN0b3Igb2YgJzMncy4gRm9yIHRoZSBDUy0sIG5vIHRyaWFscyB3ZXJlIHJlaW5mb3JjZWQgc28gaXMgYSB2ZWN0b3Igb2YgJzEyJ3MKCmBgYHtyfQoKTm9fc2NyZWFtX3AgPC0gcmVwKDMsbnN1YikKTm9fc2NyZWFtX20gPC0gcmVwKDEyLG5zdWIpCgpgYGAKCiMjIyBTY3JlYW0gcGVyIHRyaWFsIGRhdGEKCkNyZWF0ZSBkYXRhc2V0cyBmb3IgdGhlIGFjcXVpc2l0aW9uIENTLSBhbmQgZXh0aW5jdGlvbiBDUysgYW5kIENTLSByZWZsZWN0aW5nIHRoYXQgbm8gc2NyZWFtcyBvY2N1cnJlZCBhdCBhbGwuIFRoZW4gdXNlIHRoZSBwYXR0ZXJuIGlkIHZhcmlhYmxlIHRvIGNyZWF0ZSBhIGRhdGFzZXQgZm9yIHRoZSBhY3F1aXNpdGlvbiBDUysgaW5kaWNhdGluZyB3aGVuIGEgc2NyZWFtIG9jY3VycmVkIGZvciBlYWNoIHBhcnRpY2lwYW50LgpgYGB7cn0KCgojIyBDcmVhdGUgdGhlIG5vIHNjcmVhbSBkYWF0c2V0cyBmb3IgYWxsCnNjcmVhbU1pbnVzIDwtIG1hdHJpeCgwTCxucm93PW5zdWIsIG5jb2w9bnRyaWFscykKCmxpYnJhcnkoZGF0YS50YWJsZSkKCiMjIHJlYWQgaW4gdGhlIHNjcmVhbXMgZm9yIGFjcXVpc2l0aW9uIApzY3JlYW1QbHVzIDwtIGZyZWFkKCIvVXNlcnMva2lyc3Rpbi9Ecm9wYm94L1NHRFAvRkxBUmUvRkxBUmVfTUFTVEVSL1Byb2plY3RzL0xhdGVudEdyb3d0aC9EYXRhc2V0cy9iYXllc19zY3JlYW1zX2FjcS5jc3YiLGRhdGEudGFibGU9RikKCgojIAojICMjIyBmb3IgdGhlIHRpbWUgYmVpbmcsIHNpbXVsYXRlIHRoZSBOQSBkYXRhIGZvciB0aGUgc3R1ZGllcyB3aGVyZSBJIGhhdmVudCB5ZXQgZmluaXNoZWQgY2xlYW5pbmcgdGhlIHNjcmVhbXMuCiMgCiMgIyBtYWtlIHRoZSBmaXJzdCB0cmlhbCAxIGZvciBldmVyeW9uZSwgdGhlbiBhZGQgOCBhZGRpdGlvbmFsIHJhbmRvbSAxJ3MgcGVyIHBlcnNvbi4gRG8gdGhpcyBpbiBmb3VyIHJhbmRvbSBwYXR0ZXJucyB0byBtaW1pYyB0aGUgcmVhbCBkYXRhCiMgCiMgc2MxIDwtIGMoMSwxLDAsMSwwLDAsMSwxLDEsMSwxKQojIHNjMiA8LSBjKDAsMSwxLDEsMCwwLDEsMSwxLDEsMSkKIyBzYzMgPC0gYygxLDEsMSwwLDEsMCwxLDAsMSwxLDEpCiMgc2M0IDwtIGMoMSwwLDEsMSwwLDAsMSwxLDEsMSwxKQojIAojIAojIHNjcmVhbVBsdXNbLDFdIDwtIGlmZWxzZShpcy5uYShzY3JlYW1QbHVzWywxXSksMSxzY3JlYW1QbHVzWywxXSkKIyAKIyAjIGZvciAobiBpbiAxOmRpbShzY3JlYW1QbHVzKVsxXSkgewojICMgICBwcmludChuKQojICMgICBzY3JlYW1QbHVzW24sMjoxMl0gPC0gc2FtcGxlKHBhdHRzLDEscmVwbGFjZT1UKQojICMgfQojIAojIGZvciAobiBpbiAxOmRpbShzY3JlYW1QbHVzKVsxXSkgewojICAgCiMgICBhIDwtIHNhbXBsZShjKDEsNCksMSkKIyAgIAojICAgaWYgKGlzLm5hKHNjcmVhbVBsdXNbbiwyXSkpewojICAgICBpZiAoYSA9PSAxKSB7CiMgICAgICAgc2NyZWFtUGx1c1tuLDI6MTJdIDwtIHNjMQojICAgICB9IGVsc2UgaWYgKGEgPT0gMikgewojICAgICAgIHNjcmVhbVBsdXNbbiwyOjEyXSA8LSBzYzIKIyAgICAgfSBlbHNlIGlmIChhID09IDMpewojICAgICAgIHNjcmVhbVBsdXNbbiwyOjEyXSA8LSBzYzMKIyAgICAgfSBlbHNlIHsKIyAgICAgICBzY3JlYW1QbHVzW24sMjoxMl0gPC0gc2M0CiMgICAgIH0KIyAgIH0KIyB9CgpgYGAKCgoKIyMgQ3JlYXRlIGRhdGFzZXQgZm9yIGJhcnBsb3QgY29tcGFyaW5nIG91dHB1dAoKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKCm1vZF9jb21wIDwtIGRhdGEuZnJhbWUobW9kZWw9TkEsQklDPU5BKQoKYGBgCgojIyMgcmVzY2FsZSBkYXRhCgpyZXNjYWxlIHRoZSAxLTkgZXhwZWN0YW5jeSB2YWx1ZXMgdG8gYmUgb24gYSAwLTEgc2NhbGUuCgpzdGFuIGNhbm5vdCBkZWFsIHdpdGggdGhlIGV4dHJlbWUgbGltaXQgb2YgdGhlIGJldGEsIHNvIG1ha2UgdGhlIHJlc2NhbGVkIGxpbWl0cyBqdXN0IGFib3ZlIDAgYW5kIGJlbG93IG9uZQoKTm90ZSB0aGF0IHdoZW4gYSB2YWx1ZSBoYWQgdG8gYmUgaW1wdXRlZCBhcyBpdCB3YXMgbWlzc2luZyBpdCB3aWxsIG5vdCBiZSBhbiBpbnRlZ2VyLiBUaHVzIHRoZSBmdW5jdGlvbiBuZWVkcyB0byBhbGxvdyBmb3IgcmFuZ2VzIGJldHdlZW4gdmFsdWVzLgoKYGBge3J9CgpsaWJyYXJ5KHNjYWxlcykKCiMgcmVzY2FsZSBhbmQgZmxpcCBzbyB0aGF0IHdlIGFyZSBlZmZlY3RpdmVseSByYXRpbmcgdGhlIGV4cGVjdGF0aW9uIHRoYXQgdGhleSBXSUxMIE5PVCBoZWFyIGEgc2NyZWFtIHRvIG1hdGNoIHN0YW4KCiMjIHJlc2NhbGluZyBzdWNoIHRoYXQgdGhlIGRpc3RyaWJ1dGlvbiBzcGFjZXMgdGhlIG51bWJlcnMgMS05IGV2ZW5seS4gdGhlIGZpcnN0IGludGVydmFsIHVwcGVyIGJvdW5kIHdvdWxkIGJlIDAuMTEsIHRoZW4gMC4yMiBldGMuIHRoaXMgbWVhbnMgdGhhdCB0aGUgbWlkIHBvaW50IG9mIGVhY2ggaXRuZXJ2YWwgd2lsbCBiZToKCnByaW50KCJtaWQgcG9pbnQgb2YgZWFjaCBldmVubHkgc3BhY2VkIGludGVydmFsIHJlcHJlc2VudGluZyB2YWx1ZXMgYmV0d2VlbiAxLTkiKQpzZXEoMC41LzksMSwxLzkpCgoKIyMgdGh1cyAxIHdpbGwgYmUgMS0wLjA1NSBldGMuCgojIyBOT1RFOiBtaWdodCB3YW50IHRvIGNvbnNpZGVyIG1ha2luZyB0aGlzIG1vcmUgZmxleGlibGUuIGVudGVyIGluIHRoZSBudW1lciBvZiBjaG9pY2Ugb3B0aW9ucyBhcyBhIHZhcmlhYmxlIC0gd291bGQgYmUgdmVyeSBlYXN5LiBhZGQgdG8gZnVuY3Rpb24gbGlicmFyeSBhdCBsYXRlciBzdGFnZQoKc2NhbGVfZmxhcmUgPC0gZnVuY3Rpb24oeCl7CiAgCiAgdmFscyA8LSBzZXEoMC41LzksMSwxLzkpCiAgCiAgZm9yICh2YWwgaW4gMTo5KXsKICAgIGlmICh4ID4gdmFsLTEgJiB4IDw9IHZhbCl7CiAgICAgIHggPC0gMSAtIHZhbHNbdmFsXQogICAgfQogIH0KICByZXR1cm4oeCkKfQoKCiMjIGluaXRpYWxpc2UgbWludXNfc2NhbGVkIGRhdGFmcmFtZS4KCm1pbnVzX3NjYWxlZCA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPWRpbShtaW51cylbMl0sbnJvdyA9IGRpbShtaW51cylbMV0pKQoKIyMgIHBvcHVsYXRlIHdpdGggcmV4Y2FsZWQgdmFsdWVzCgpmb3IgKHN1YiBpbiAxOmRpbShtaW51cylbMV0pewogIGZvciAoY29sIGluIDE6ZGltKG1pbnVzKVsyXSl7CiAgICAKICAgIG1pbnVzX3NjYWxlZFtzdWIsY29sXSA8LSBzY2FsZV9mbGFyZShtaW51c1tzdWIsY29sXSkKICB9Cn0KCiMjIGRpdHRvIGZvciBwbHVzCgpwbHVzX3NjYWxlZCA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPWRpbShtaW51cylbMl0sbnJvdyA9IGRpbShtaW51cylbMV0pKQoKZm9yIChzdWIgaW4gMTpkaW0ocGx1cylbMV0pewogIGZvciAoY29sIGluIDE6ZGltKHBsdXMpWzJdKXsKICAgIAogICAgcGx1c19zY2FsZWRbc3ViLGNvbF0gPC0gc2NhbGVfZmxhcmUocGx1c1tzdWIsY29sXSkKICB9Cn0KCgoKIyMgdGhpcyBpcyB0aGUgbnVtYmVyIHRoYXQgd2lsbCB0YWtlIGZyb20gdGhlIG1pZHBvaW50IHRvIHRoZSB0b3AgYW5kIGJvdHRvbSBmb3IgdGhlIG5ldyBib3VuZGFyaWVzICh3aXRoIHJhdGluZ3MgcmVwcmVzZW50aW5nIHRoZSBtaWRwb2ludCkKCmNkZl9zY2FsZSA8LSAxLzE4CgoKCgpgYGAKCgojIyBTZXQgdXAgc3RhbiAKCgpUaGVzZSB1c2UgQWxleCBQaWtlcyBSU3RhbiBzY3JpcHQgd2l0aCBtaW5vciBtb2RpZmljYXRpb24gdG8gbWFrZSBpdCBwdW5pc2htZW50IG9ubHkgdG8gc2VlIGlmIGl0IHJ1bnMuIFRlc3RpbmcgdGhhdCB0aGUgYXBwcm9hY2ggd29ya3Mgd2l0aCB0aGUgY3VycmVudCBkYXRhIHNldCB1cCBldGMuICAKClRoZSBzZXR0aW5ncyBmb3IgdGhlIHNjcmlwdCBhcmUgYmVsb3csIGluY2x1ZGluZyBzdGFuIGNoYWluIHBhcmFtZXRlcnMgYW5kIGRpcmVjdG9yeSBzZXQgdXAuCgoKClRoaXMgbG9hZHMgdGhlIGxpYnJhcmllcyBhbmQgc291cmNlIGZpbGVzIG5lZWRlZCB0byBydW4gdGhpcyBzY3JpcHQsIGFuZCBzZXRzIHVwIFJTdGFuCgpgYGB7ciwgZWNobyA9IEYscmVzdWx0cz0naGlkZScsbWVzc2FnZT1GfQoKIyBsaWJyYXJpZXMgYW5kIHNvdXJjZSBmaWxlcyAKbGlicmFyeSgnTUFTUycpCmxpYnJhcnkoJ2Jvb3QnKQpsaWJyYXJ5KCdkcGx5cicpCmxpYnJhcnkoJ3Jlc2hhcGUnKQpsaWJyYXJ5KCd0aWR5cicpCmxpYnJhcnkoJ3JzdGFuJykgCmxpYnJhcnkoJ2xvbycpICAgICMgdGhpcyBpcyBtb2RlbCBjb21wYXJpc29uIHBhY2thZ2UuIGhlbHBzIGV4dHJhY3QgbG9nbGlrZWxpaG9vZCB0b28uCmxpYnJhcnkoJ2RhdGEudGFibGUnKQoKI29wdGlvbnMgZm9yIFJTVEFOCm9wdGlvbnMobWMuY29yZXMgPSBwYXJhbGxlbDo6ZGV0ZWN0Q29yZXMoKSkKcnN0YW5fb3B0aW9ucyhhdXRvX3dyaXRlID0gVFJVRSkKU3lzLnNldGVudihMT0NBTF9DUFBGTEFHUyA9ICctbWFyY2g9bmF0aXZlJykKU3lzLmdldGVudignTE9DQUxfQ1BQRkxBR1MnKSAjc2hvdWxkIHNheSAnLW1hcmNoPW5hdGl2ZScKCiNmdW5jdGlvbnMgKGlmIGFuZCB3aGVuIHJlbGV2YW50IGFuZCBhZGRlZCkKIyBzb3VyY2UoJy9Vc2Vycy9raXJzdGluL0Ryb3Bib3gvU0dEUC9GdW5jdGlvbl9saWJyYXJ5Lzw8ZnVuY3Rpb24gc2NyaXB0IG5hbWU+PicpCnNvdXJjZSgnL1VzZXJzL2tpcnN0aW4vRHJvcGJveC9TR0RQL0Z1bmN0aW9uX2xpYnJhcnkvbm90X2luLlInKSAjIE5vdCBpbiAlIWluJSBmdW5jdGlvbgoKYGBgCgojIyBTdGFuIGRhdGEKCmBgYHtyIHN0YW4gZGF0YX0KCiMjIFRlc3QgZGF0YSAoUGlsb3QgKyBUUlQgKyBWYWxpZGF0aW9uKSBwcm9wb3J0aW9uIG5vIHNjcmVhbXMKCgojZGF0YQpkYXRhX2ZpbGVzPC1saXN0KG50cmlhbHM9bnRyaWFscyxuc3ViPW5zdWIsbm90aGluZ1BsdXMgPSBOb19zY3JlYW1fcCwgbm90aGluZ01pbnVzPU5vX3NjcmVhbV9tLHJhdGluZ3NQbHVzPXBsdXNfc2NhbGVkLHJhdGluZ3NNaW51cz1taW51c19zY2FsZWQpCgoKIyMgVGVzdCBkYXRhIChQaWxvdCArIFRSVCArIFZhbGlkYXRpb24pIHByb3BvcnRpb24gc2NyZWFtcywgbm8gbG9nIGxpa2VsaWhvb2QKCmZsYXJlX2RhdGFfbm9sb2cgPC1saXN0KG50cmlhbHM9bnRyaWFscyxuc3ViPW5zdWIsc2NyZWFtUGx1cyA9IHQoc2NyZWFtUGx1cyksIHNjcmVhbU1pbnVzPSB0KHNjcmVhbU1pbnVzKSxyYXRpbmdzUGx1cz10KHBsdXNfc2NhbGVkKSxyYXRpbmdzTWludXM9dChtaW51c19zY2FsZWQpKQoKIyMgVGVzdCBkYXRhIChQaWxvdCArIFRSVCArIFZhbGlkYXRpb24pIHByb3BvcnRpb24gc2NyZWFtcywgbm8gbG9nIGxpa2VsaWhvb2QKZmxhcmVfZGF0YTwtbGlzdChudHJpYWxzPW50cmlhbHMsbnN1Yj1uc3ViLHNjcmVhbVBsdXMgPSB0KHNjcmVhbVBsdXMpLCBzY3JlYW1NaW51cz10KHNjcmVhbU1pbnVzKSxyYXRpbmdzUGx1cz10KHBsdXNfc2NhbGVkKSxyYXRpbmdzTWludXM9dChtaW51c19zY2FsZWQpLGNkZl9zY2FsZT1jZGZfc2NhbGUpCgoKIyMgVmFsaWRhdGlvbiBkYXRhIChURURTKSBzY2FsZWQgCiMgCiMgVEVEU19kYXRhPC1saXN0KG50cmlhbHM9bnRyaWFscyxuc3ViPW5zdWIsc2NyZWFtUGx1cyA9IHQoc2NyZWFtUGx1cyksIHNjcmVhbU1pbnVzPSB0KHNjcmVhbU1pbnVzKSxyYXRpbmdzUGx1cz10KHBsdXNfc2NhbGVkKSxyYXRpbmdzTWludXM9dChtaW51c19zY2FsZWQpKQoKYGBgCgojIEJhc2VsaW5lIG1vZGVscwoKIyMgTW9kZWwgMTogc2luZ2xlIGJldGEgbm8gc2NhbGluZyB7LnRhYnNldH0KCiMjIyBub3RlcwoKQmVjYXVzZSB3ZSB1c2UgdGhlIDEtcmVzY2FsZWQgZXhwZWN0YW5jeSBkYXRhLCBubyBuZWVkIHRvIHRyeSBhbmQgaW52ZXJ0IHRvIHJlaW5mb3JjZW1lbnQgcGFyYW1ldGVycyBoZXJlLiBBcyBhIHJlc3VsdCB3ZSBuZWVkIHRoZSBzdGFuIG1vZGVsIHRvIHNpbXBseSBiZTogICAKCmBgYAphbHBoYVBsdXNbcF0gPSAgbm90aGluZ1BsdXNbcF0vbnRyaWFsczsKYWxwaGFNaW51c1twXSA9ICBub3RoaW5nTWludXNbcF0vbnRyaWFsczsKYGBgCgojIyMgcnVuIEFsZXggUGlrZSdzIHN0YW4gc2NyaXB0IGZvciBub24gc2NhbGVkIGJldGEgbW9kZWwuCgpoZXJlIHdlIHRyeSB0byBlc3RpbWF0ZSB0aGUgYWxwaGEgcGFyYW1ldGVyIG9mIHRoZSBiZXRhIGRpc3RyaWJ1dGlvbiBwZXIgdHJpYWwgcGVyIHBlcnNvbiBwZXIgc3RpbXVsdXMuIChpLmUuIHlvdSBoYXZlIHR3byBzdWZmaWNpZW50IHBhcmFtZXRlcnMgZm9yIGVhY2ggYmV0YSBkaXN0LCB0aGUgYWxwaGEgYW5kIGJldGEuIHdlIHdhbnQgdG8gZXN0aW1hdGUgdGhlIGFscGhhIC0gKS4gCgpFdmVudHVhbGx5IHdlIHdpbGwgc2NhbGUgdGhlc2UgYnkgdGhlIGFjdHVhbCAndmFsdWUnIG9mIHRoZSBzY3JlYW0gZm9yIGVhY2ggcGVyc29uIHBlciB0cmlhbC4gCgpVc2luZyBkYXRhIGxvYWRlZCBpbiBmcm9tIHByZWxpbWluYXJ5IHRlc3RzIGFib3ZlLgoKc28gdGhpcyBpcyBhIGJldGEgdmFsdWUgcGVyIHBlcnNvbiAoYXNzdW1pbmcgdGhlIHVuZGVybHlpbmcgcHJvY2VzcyBmb3IgdGhlIHBsdXMgYW5kIG1pbnVzIGFyZSB0aGUgc2FtZSkKCiMjIyBNb2RlbAoKYGBge3Igbm8gc2NhbGluZyBzZXQgdXB9CiNzY3JpcHQKc3Rhbm5hbWU9J2JldGFfbm9zY2FsaW5nLnN0YW4nCgojZGF0YQpkYXRhX2ZpbGVzPC1saXN0KG50cmlhbHM9bnRyaWFscyxuc3ViPW5zdWIsbm90aGluZ1BsdXMgPSBOb19zY3JlYW1fcCwgbm90aGluZ01pbnVzPU5vX3NjcmVhbV9tLHJhdGluZ3NQbHVzPXBsdXNfc2NhbGVkLHJhdGluZ3NNaW51cz1taW51c19zY2FsZWQpCgpgYGAKCmBgYHtyIGJldGEgbm8gc2NhbGluZ30KCmZsYXJlX2ZpdCA8LSBtb2RlbF9ydW4oJ2xvYWQnLCdiZXRhX25vc2NhbGluZy5zdGFuJyxkYXRhX2ZpbGVzKQoKIyMgZ2V0IHNvbWUgYmFzaWMgb3V0cHV0IGRlc2NyaXB0aW9ucyBwcmludGVkIHRvIHNjcmVlbgpvdXRfZGVzY3JpYmUoZmxhcmVfZml0LG5zdWIpCgojIGV4dHJhY3QgZml0IGRhdGEKc3VtbWFyeV9mbGFyZSA8LSBzdW1tYXJ5KGZsYXJlX2ZpdCkKCmBgYAoKCiMjIE1vZGVsIDI6IHNpbmdsZSBiZXRhIHNjYWxlZCB7LnRhYnNldH0KCiMjIyBub3RlcwoKU2ltcGxlIGFsdGVyYXRpb24gb2YgdGhlIGZpcnN0IG1vZGVsLiBXZSBlc3RpbWF0ZSBhIHNjYWxpbmcgcGFyYW1ldGVyIHBlciBwZXJzb24gb3ZlciBhbGwgdHJpYWxzIGFuZCBhcHBseSB0aGlzIHRvIGFscGhhIGNvbXBvbmVudCBwZXIgcGFydGljaXBhbnQuCgojIyMgcnVuIEFsZXggUGlrZSdzIHN0YW4gc2NyaXB0IGZvciBzY2FsZWQgYmV0YSBtb2RlbC4KCmhlcmUgd2UgdHJ5IHRvIGVzdGltYXRlIHRoZSBhbHBoYSBwYXJhbWV0ZXIgb2YgdGhlIGJldGEgZGlzdHJpYnV0aW9uIHBlciB0cmlhbCBwZXIgcGVyc29uIHBlciBzdGltdWx1cy4gKGkuZS4geW91IGhhdmUgdHdvIHN1ZmZpY2llbnQgcGFyYW1ldGVycyBmb3IgZWFjaCBiZXRhIGRpc3QsIHRoZSBhbHBoYSBhbmQgYmV0YS4gd2Ugd2FudCB0byBlc3RpbWF0ZSB0aGUgYWxwaGEgLSApLiAKCkV2ZW50dWFsbHkgd2Ugd2lsbCBzY2FsZSB0aGVzZSBieSB0aGUgYWN0dWFsICd2YWx1ZScgb2YgdGhlIHNjcmVhbSBmb3IgZWFjaCBwZXJzb24gcGVyIHRyaWFsLiAKClVzaW5nIGRhdGEgbG9hZGVkIGluIGZyb20gcHJlbGltaW5hcnkgdGVzdHMgYWJvdmUuCgpzbyB0aGlzIGlzIGEgYmV0YSB2YWx1ZSBwZXIgcGVyc29uIChhc3N1bWluZyB0aGUgdW5kZXJseWluZyBwcm9jZXNzIGZvciB0aGUgcGx1cyBhbmQgbWludXMgYXJlIHRoZSBzYW1lKQoKIyMjIE1vZGVsCgpgYGB7ciBzY2FsZWQgIHNldCB1cCxlY2hvPUZ9Cgojc2NyaXB0CnN0YW5uYW1lPSdiZXRhX3NjYWxpbmcuc3RhbicKCmBgYAoKYGBge3IgYmV0YSBzY2FsZWR9CgpmbGFyZV9maXQgPC0gbW9kZWxfcnVuKCdsb2FkJyxzdGFubmFtZSxkYXRhX2ZpbGVzKQoKIyMgZ2V0IHNvbWUgYmFzaWMgb3V0cHV0IGRlc2NyaXB0aW9ucyBwcmludGVkIHRvIHNjcmVlbgpvdXRfZGVzY3JpYmUoZmxhcmVfZml0LG5zdWIpCgojIGV4dHJhY3QgZml0IGRhdGEKc3VtbWFyeV9mbGFyZSA8LSBzdW1tYXJ5KGZsYXJlX2ZpdCkKCmBgYAoKCiMjIyBydW4gQWxleCBQaWtlJ3Mgc3RhbiBzY3JpcHQgZm9yIHNjYWxlZCBiZXRhIG1vZGVsLgoKaGVyZSB3ZSB0cnkgdG8gZXN0aW1hdGUgdGhlIGFscGhhIHBhcmFtZXRlciBvZiB0aGUgYmV0YSBkaXN0cmlidXRpb24gcGVyIHRyaWFsIHBlciBwZXJzb24gcGVyIHN0aW11bHVzLiAoaS5lLiB5b3UgaGF2ZSB0d28gc3VmZmljaWVudCBwYXJhbWV0ZXJzIGZvciBlYWNoIGJldGEgZGlzdCwgdGhlIGFscGhhIGFuZCBiZXRhLiB3ZSB3YW50IHRvIGVzdGltYXRlIHRoZSBhbHBoYSAtICkuIAoKRXZlbnR1YWxseSB3ZSB3aWxsIHNjYWxlIHRoZXNlIGJ5IHRoZSBhY3R1YWwgJ3ZhbHVlJyBvZiB0aGUgc2NyZWFtIGZvciBlYWNoIHBlcnNvbiBwZXIgdHJpYWwuIAoKVXNpbmcgZGF0YSBsb2FkZWQgaW4gZnJvbSBwcmVsaW1pbmFyeSB0ZXN0cyBhYm92ZS4KCnNvIHRoaXMgaXMgYSBiZXRhIHZhbHVlIHBlciBwZXJzb24gKGFzc3VtaW5nIHRoZSB1bmRlcmx5aW5nIHByb2Nlc3MgZm9yIHRoZSBwbHVzIGFuZCBtaW51cyBhcmUgdGhlIHNhbWUpCgoKYGBge3IgYmV0YSBSTCBzZXQgdXB9CiNzY3JpcHQKc3Rhbm5hbWU9J2JldGFfd2l0aFJMLnN0YW4nCgpgYGAKCmBgYHtyIGJldGEgUkx9CgpmbGFyZV9maXQgPC0gbW9kZWxfcnVuKCdsb2FkJyxzdGFubmFtZSxmbGFyZV9kYXRhX25vbG9nKQoKIyMgZ2V0IHNvbWUgYmFzaWMgb3V0cHV0IGRlc2NyaXB0aW9ucyBwcmludGVkIHRvIHNjcmVlbgpvdXRfZGVzY3JpYmUoZmxhcmVfZml0LG5zdWIpCgojIGV4dHJhY3QgZml0IGRhdGEKc3VtbWFyeV9mbGFyZSA8LSBzdW1tYXJ5KGZsYXJlX2ZpdCkKCmBgYAoKCiMjIE1vZGVsIDM6IFJMLCBtZWFuIGRlZmluZWQsIHNpbmdsZSBiZXRhIHsudGFic2V0fQoKIyMjIG5vdGVzCgp0aGlzIG1vZGVsIGluY2x1ZGVzIGFuIGFscGhhIGxlYXJuaW5nIHBhcmFtYXRlciBwZXIgcGVyc29uIGVzdGltYXRpbmcgdGhlaXIgbGVhcm5pbmcgcmF0ZSBhbmQgdXBkYXRpbmcgYmFzZWQgb24gaXQuIFRoaXMgbW9kZWwgbmVlZHMgYSBkYXRhc2V0IHRoYXQgaW5kaWNhdGVzIHdoZXRoZXIgYSBzY3JlYW0gb2NjdXJyZWQgZm9yIGVhY2ggdHJpYWwgaW5zdGVhZCBvZiB0aGUgcHJvcG9ydGlvbiBvZiB0aW1lcyBubyBzY3JlYW0gb2NjdXJyZWQuCgoKIyMjIE1lYW4gdG8gZGVmaW5lIHNoYXBlCgp0aGlzIG1vZGVsIGluY2x1ZGVzIGFuIGFscGhhIGxlYXJuaW5nIHBhcmFtYXRlciBwZXIgcGVyc29uIGVzdGltYXRpbmcgdGhlaXIgbGVhcm5pbmcgcmF0ZSBhbmQgdXBkYXRpbmcgYmFzZWQgb24gaXQuIFRoaXMgbW9kZWwgbmVlZHMgYSBkYXRhc2V0IHRoYXQgaW5kaWNhdGVzIHdoZXRoZXIgYSBzY3JlYW0gb2NjdXJyZWQgZm9yIGVhY2ggdHJpYWwgaW5zdGVhZCBvZiB0aGUgcHJvcG9ydGlvbiBvZiB0aW1lcyBubyBzY3JlYW0gb2NjdXJyZWQuCgpBbGV4IHVzZWQgdGhpcyBbc3RhY2sgcG9zdF0oaHR0cHM6Ly9zdGF0cy5zdGFja2V4Y2hhbmdlLmNvbS9xdWVzdGlvbnMvMTIyMzIvY2FsY3VsYXRpbmctdGhlLXBhcmFtZXRlcnMtb2YtYS1iZXRhLWRpc3RyaWJ1dGlvbi11c2luZy10aGUtbWVhbi1hbmQtdmFyaWFuY2UpIHRvIGhlbHAgc29sdmUgdGhlIHNoYXBlIHBhcmFtZXRlcnMgdXNpbmcgbWVhbiBhbmQgc2Qgd2hlcmUgd2UgYXNzdW1lIHRoYXQgdiBzZXJ2ZXMgYXMgdGhlIG1lYW4gYW5kIGJldGEgYXMgdGhlIHNkLgoKdGhlIGVxdWF0aW9ucyB3b3JrIG91dCB0byB0aGlzOgoKZm9yIHNoYXBlIDE6IAoKCiQkXGFscGhhID0gXGxlZnQoXGZyYWN7MS1cbXV9e1xzaWdtYV4yfSAtIFxmcmFjezF9e1xtdX1ccmlnaHQpXG11XjIkJAoKZm9yIHNoYXBlIDI6IAoKJCRcYmV0YT1cYWxwaGEgXGxlZnQoXGZyYWN7MX17XG11fS0xXHJpZ2h0KSQkCiMjIyBNb2RlbAoKdGhpcyB3YXkgb2YgZGVmaW5pbmcgdGhlIG1lYW4gZG9lcyBub3Qgd29yayBvciBldmVuIHJ1biwgc28gc2tpcHBpbmcgaXQuCgpgYGB7ciBtZWFuIDEgc2V0IHVwfQojc2NyaXB0CnN0YW5uYW1lPSdiZXRhX21lYW5zZF9STC5zdGFuJwoKYGBgCgoKYGBge3IgbWVhbiAxfQoKZmxhcmVfZml0IDwtIG1vZGVsX3J1bignc2tpcCcsc3Rhbm5hbWUsZmxhcmVfZGF0YV9ub2xvZykKCiMjIGdldCBzb21lIGJhc2ljIG91dHB1dCBkZXNjcmlwdGlvbnMgcHJpbnRlZCB0byBzY3JlZW4Kb3V0X2Rlc2NyaWJlKGZsYXJlX2ZpdCxuc3ViKQoKIyBleHRyYWN0IGZpdCBkYXRhCnN1bW1hcnlfZmxhcmUgPC0gc3VtbWFyeShmbGFyZV9maXQpCgpgYGAKCgpPbiA1MDAgaXRlcmF0aW9ucyAoaS5lLiB0ZXN0KSB0aGUgdmFyaWFuY2UgaW4gYWxwaGEgaXMgZ29vZCwgYnV0IHRoZSB0cmFjZXBsb3QgaXMgdGVycmlibGUuIE1vZGVsIGNvdmVyZ2VzIHZlcnkgcG9vcmx5LiBXZSBhbHNvIGhhdmUgdG8gY29uc3RyYWluIHRoZSBiZXRhIHRvIGJlIGJldHdxZWVuIDAgYW5kIDAuMDAwMS4gTm90IHN1cmUgd2h5IHRoaXMgaXMuIAoKd2hlbiBydW5uaW5nIGZvciAyMDAwIGl0ZXJhdGlvbnMgKDEwMDAgd2FybXVwKS4uLgoKVGhpcyByZXN1bHRzIGluIHRoZSBmb2xsb3dpbmcgd2FybmluZzsKCj4+IFRoZXJlIHdlcmUgMjY0NCBkaXZlcmdlbnQgdHJhbnNpdGlvbnMgYWZ0ZXIgd2FybXVwLiBJbmNyZWFzaW5nIGFkYXB0X2RlbHRhIGFib3ZlIDAuOCBtYXkgaGVscC4gU2VlCmh0dHA6Ly9tYy1zdGFuLm9yZy9taXNjL3dhcm5pbmdzLmh0bWwjZGl2ZXJnZW50LXRyYW5zaXRpb25zLWFmdGVyLXdhcm11cFRoZXJlIHdlcmUgNCB0cmFuc2l0aW9ucyBhZnRlciB3YXJtdXAgdGhhdCBleGNlZWRlZCB0aGUgbWF4aW11bSB0cmVlZGVwdGguIEluY3JlYXNlIG1heF90cmVlZGVwdGggYWJvdmUgMTAuIFNlZQpodHRwOi8vbWMtc3Rhbi5vcmcvbWlzYy93YXJuaW5ncy5odG1sI21heGltdW0tdHJlZWRlcHRoLWV4Y2VlZGVkVGhlcmUgd2VyZSA0IGNoYWlucyB3aGVyZSB0aGUgZXN0aW1hdGVkIEJheWVzaWFuIEZyYWN0aW9uIG9mIE1pc3NpbmcgSW5mb3JtYXRpb24gd2FzIGxvdy4gU2VlCmh0dHA6Ly9tYy1zdGFuLm9yZy9taXNjL3dhcm5pbmdzLmh0bWwjYmZtaS1sb3dFeGFtaW5lIHRoZSBwYWlycygpIHBsb3QgdG8gZGlhZ25vc2Ugc2FtcGxpbmcgcHJvYmxlbXMKCiMjIyBNZWFuIGRlZmluaXRpb24gMgoKVGhlIGFib3ZlIG1lYW4gZGVmaW5pdGlvbiBkb2VzIG5vdCBtYXAgdGhlIGRhdGEgd2VsbCAodGVycmlibGUgdHJhY2VwbG90ISkuIEkgZm91bmQgW3RoaXMgZnJvbSB0aGUgTVJDIEJTVV0oaHR0cHM6Ly93d3cubXJjLWJzdS5jYW0uYWMudWsvd3AtY29udGVudC91cGxvYWRzL2J1Z3Nib29rX2NoYXB0ZXI1LnBkZikgYW5kIGhhdmUgdHJpZWQgZGVmaW5pbmcgdGhlIGJldGEgcGFyYW1ldGVycyBhc3N1bWluZyBWID09IG1lYW4gaW4gYSBzbGlnaHR5IGRpZmZlcmVudCB3YXk6Cgpmb3IgcGFyYW1hdGVyIGE6CgokJFxhbHBoYSA9IFxtdVxiZXRhLygxLVxtdSkkJAoKZm9yIHBhcmFtZXRlciBiOgoKJCRcYmV0YSA9IFxtdSgxLVxtdSleMi9cc2lnbWErXG11LTEkJAoKIyMjIE1vZGVsCgpTdGlsbCB1c2luZyBhIHNpbmdsZSBiZXRhIGhlcmUuCgpza2lwcGluZyBhcyBpdCBhbHNvIGRvZXMgbm90IHJ1bgoKYGBge3IgbWVhbiAyIHNldCB1cH0KI3NjcmlwdApzdGFubmFtZT0nYmV0YV9tZWFuc2RfUkxfMi5zdGFuJwoKYGBgCgoKYGBge3IgbWVhbiAyfQoKZmxhcmVfZml0IDwtIG1vZGVsX3J1bignc2tpcCcsc3Rhbm5hbWUsZmxhcmVfZGF0YV9ub2xvZykKCiMjIGdldCBzb21lIGJhc2ljIG91dHB1dCBkZXNjcmlwdGlvbnMgcHJpbnRlZCB0byBzY3JlZW4Kb3V0X2Rlc2NyaWJlKGZsYXJlX2ZpdCxuc3ViKQoKIyBleHRyYWN0IGZpdCBkYXRhCnN1bW1hcnlfZmxhcmUgPC0gc3VtbWFyeShmbGFyZV9maXQpCgpgYGAKCgojIyMgTWVhbiBkZWZpbml0aW9uIDMKCm5vdGVkIHRoYXQgdGhlIHNoYXBlIHBhcmFtZXRlcnMgaGF2ZSAgc2xpZ2h0IHZhcmlhdGlvbnMgaW4gZGVmaW5pdGlvbiBhY2NvcmRpbmcgdG8gZGlzY3Vzc2lvbiBbaGVyZV0oaHR0cHM6Ly9zdGF0cy5zdGFja2V4Y2hhbmdlLmNvbS9xdWVzdGlvbnMvMTIyMzIvY2FsY3VsYXRpbmctdGhlLXBhcmFtZXRlcnMtb2YtYS1iZXRhLWRpc3RyaWJ1dGlvbi11c2luZy10aGUtbWVhbi1hbmQtdmFyaWFuY2UpLiBVcGRhdGVkIHRoZSBzY3JpcHQgc2xpZ2h0bHkgdG8gcmVmbGVjdCB0aGlzIGJhc2VkIG9uIHRoZSByZXBseSBmcm9tIG9jcmFtLgoKdGhlIGZpcnN0IHNkIHRlcm0gaW4gc2hhcGUgYSBpcyBjaGFuZ2VkIHRvIHZhcmlhbmNlLCBzbyBpdCBjaGFuZ2VzIGZyb206ICAgCgokJFxhbHBoYSA9IFxsZWZ0KFxmcmFjezEtXG11fXtcc2lnbWFeMn0gLSBcZnJhY3sxfXtcbXV9XHJpZ2h0KVxtdV4yJCQKCnRvIAoKJCRcYWxwaGEgPSBcbGVmdChcZnJhY3sxLVxtdX17XHNpZ21hfSAtIFxmcmFjezF9e1xtdX1ccmlnaHQpXG11XjIkJAoKCkNoYW5nZXMgdGhlIHNoYXBlIDIgcGFyYW1ldGVyIGRlZmluaXRpb24gZnJvbToKCiQkXGJldGE9XGFscGhhIFxsZWZ0KFxmcmFjezF9e1xtdX0tMVxyaWdodCkkJCAgIAoKdG8gCgoKJCRcYmV0YSA9IFxsZWZ0KFxmcmFjezEtXG11fXtcc2lnbWF9IC0gXGZyYWN7MX17XG11fVxyaWdodClcbXVcbGVmdCgxLVxtdVxyaWdodCkkJAoKQmVjYXVzZSB0aGlzIHdvcmtzIGJlc3QsIHdpbGwgYWRkIGxvZ2xpa2VsaWhob2QgY2FsY3VsYXRpb24gaGVyZS4gQmFzaW5nIHRoaXMgb24gdGhlIHByb2JhYmlsaXR5IGRlbnNpdHkgZnVuY3Rpb24gZm9yIHRoZSBiZXRhIGRpc3RyaWJ1dGlvbiBnaXZlbiB0aGUgcGFydGljaXBhbnRzIGFjdHVhbCByYXRpbmdzIGFuZCBzdWZmaWNpZW50IHBhcmFtZXRlcnMgb2YgdGhlIGRpc3RyaWJ1dGlvbiBwZXIgdHJpYWwuCgo+Pj5sb2dsaWtbcF0gPSAgbG9nbGlrW3BdICsKICAgICAgICAgYmV0YV9scGRmKHJhdGluZ3NQbHVzW3QscF18c2hhcGUxX1BsdXNbdCxwXSxzaGFwZTJfUGx1c1t0LHBdKSArCiAgICAgICAgIGJldGFfbHBkZihyYXRpbmdzTWludXNbdCxwXXxzaGFwZTFfTWludXNbdCxwXSxzaGFwZTJfTWludXNbdCxwXSkKICAgICAgICAgCiAgICAgICAgIAojIyMgTW9kZWwKICAgICAgICAgClNraXAgYXMgdGhpcyBkZWZpbml0aW9uIGFsc28gZG9lcyBub3Qgd29yayBvciBydW4KCgpgYGB7ciBtZWFuIDMgc2V0IHVwfQojc2NyaXB0CnN0YW5uYW1lPSdiZXRhX21lYW5zZF9STF8zLnN0YW4nCgpgYGAKCgpgYGB7ciBtZWFuIDN9CgpmbGFyZV9maXQgPC0gbW9kZWxfcnVuKCdza2lwJyxzdGFubmFtZSxmbGFyZV9kYXRhX25vbG9nKQoKIyMgZ2V0IHNvbWUgYmFzaWMgb3V0cHV0IGRlc2NyaXB0aW9ucyBwcmludGVkIHRvIHNjcmVlbgpvdXRfZGVzY3JpYmUoZmxhcmVfZml0LG5zdWIpCgojIGV4dHJhY3QgZml0IGRhdGEKc3VtbWFyeV9mbGFyZSA8LSBzdW1tYXJ5KGZsYXJlX2ZpdCkKCmBgYAoKClRoaXMgbW9kZWwgaXMgc3Vic3RuYXRpYWxseSBiZXR0ZXIgdGhhbiBlaXRoZXIgb2YgdGhlIG90aGVyIHR3by4gVHJhY2VwbG90IHN1Z2dlc3RzIHRoYXQgdGhlIGl0ZXJhdGlvbnMgY29udmVyZ2UgYXMgd2Ugd291bGQgbGlrZS4gSG93ZXZlciwgd2Ugc3RpbGwgbmVlZCB0byBtYXNzaXZlbHkgY29uc3RyYWluIHRoZSBiZXRhIChpLmUuIGNvbmZpZGVuY2UgLyB1bmNlcnRhaW50eSkgZXN0aW1hdGVzIGZvciBpdCB0byBydW4sIG90aGVyd2lzZSB0aGUgc3RhcnRpbmcgdmFsdWVzIGRyb3AgYmVsb3cgemVyby4gCgoKIyMjIE1lYW4gZGVmaW5pdGlvbiA0CgpIZXJlIEkgdHJ5IHRvIGRlZmluZSB0aGUgcGFyYW1ldGVyIHVzaW5nIHNpbXBsaWZpZWQgbWVhbiBhbmQgcHJlY2lzaW9uIGVzdGltYXRlcyBhcyBwZXIgW3RoaXMgdHV0b3JpYWxdKGh0dHA6Ly9xdWFudGRldmVsLmNvbS9wdWJsaWMvQ1NQMjAxNy9Nb2RlbGluZ1Byb3BvcnRpb25zQW5kUHJvYmFiaWxpdGllcy5wZGYpLiBTZWUgaW4gcGFydGljdWxhciB0aGUgcGFyYW1ldGVyIGVzdGltYXRpb24gb24gdGhlIGN1YnMgZGF0YS4KCgpUaGlzIHJlc3VsdHMgaW4gYSByZWxhdGl2ZWx5IHNpbXBsaWZpZWQgcGFyYW1ldGVyIGVzdGltYXRpb24gY29tcGFyZWQgdG8gbW9kZWwgMy4gCgokJFxhbHBoYSA9IFxtdSAqICgoXG11ICogKDEtXG11KSkgLyBcc2lnbWEgLSAxKSQkCgp3aGVyZSBtdSBpcyB0aGUgbWVhbiAob3IgdmFsdWUpIGFuZCBzaWdtYSBpcyB0aGUgdmFyaWFuY2UgLyB1bmNlcnRhaW50eSBwYXJhbWV0ZXIgd2UgY3VycmVudGx5IGNhbGwgYmV0YS4KCmFuZCB0aGUgYiAob3Igc2hhcGUgMikgcGFyYW1ldGVyIGZvciB0aGUgZGlzdHJpYnV0aW9uIGlzOgoKJCRcYmV0YSA9ICgxLSBcbXUpICogKChcbXUgKiAoMS1cbXUpKSAvIFxzaWdtYSAtIDEpJCQKCiMjIyBNb2RlbAoKYGBge3IgbWVhbiA0IHNldCB1cH0KI3NjcmlwdApzdGFubmFtZT0nYmV0YV9tZWFuc2RfUkxfNC5zdGFuJwoKYGBgCgoKYGBge3IgbWVhbiA0fQoKZmxhcmVfZml0IDwtIG1vZGVsX3J1bignbG9hZCcsc3Rhbm5hbWUsZmxhcmVfZGF0YSkKCiMjIGdldCBzb21lIGJhc2ljIG91dHB1dCBkZXNjcmlwdGlvbnMgcHJpbnRlZCB0byBzY3JlZW4Kb3V0X2Rlc2NyaWJlKGZsYXJlX2ZpdCxuc3ViKQoKIyBleHRyYWN0IGZpdCBkYXRhCnN1bW1hcnlfZmxhcmUgPC0gc3VtbWFyeShmbGFyZV9maXQpCgpgYGAKCgoKIyMjIyBDcmVhdGUgQklDIGZyb20gbG9nIGxpa2VsaWhvb2QKCmBgYHtyfQojIyBleHRyYWN0IGxvZyBsaWtlbGlob29kCgpmbGFyZV9sb2dsaWtlIDwtIGV4dHJhY3RfbG9nX2xpayhmbGFyZV9maXQsIHBhcmFtZXRlcl9uYW1lID0gImxvZ2xpayIsIG1lcmdlX2NoYWlucyA9IFRSVUUpCgojY2FsY3VsYXRlIEJJQwoKRkxBUmVfYmljPC1iaWMobnRyaWFscywtY29sTWVhbnMoZmxhcmVfbG9nbGlrZV9iZXN0KSwyKSAjbnVtYmVyIG9mIHBhcmFtZXRlcnMgaW4gdGhhdCBtb2RlbCBlLmcuIDQpCgojIyBtZWFuIEJJQyBhcyBtb2RlbCBjb21wYXJpc29ucyB0b29sOgoKcHJpbnQoIk1lYW4gQmF5ZXNpYW4gaW5mb3JtYXRpb24gY3JpdGVyaW9uIGZvciBtb2RlbCIpCm1lYW4oRkxBUmVfYmljKQoKYGBgCgoKIyMjIyBBZGQgdG8gYmFyIHBsb3QKCmBgYHtyfQoKbW9kX2NvbXAgPC0gcmJpbmQobW9kX2NvbXAsYygiTWVhbnMgMSBiZXRhIixhcy5udW1lcmljKG1lYW4oRkxBUmVfYmljKSkpKQoKbW9kX2NvbXAkQklDIDwtIG9kcChhcy5udW1lcmljKG1vZF9jb21wJEJJQykpCgptb2RfY29tcCA8LSBhcy5kYXRhLmZyYW1lKG5hLm9taXQobW9kX2NvbXApKQoKIyMgcGxvdCBmdW5jdGlvbiAtIGNyZWF0ZSBwbG90CnBsb3RfbW9kZWxzKG1vZF9jb21wKQoKYGBgCgoKIyMgTW9kZWwgNDogUkwsIG1vZGUgZGVmaW5lZCwgc2luZ2xlIGJldGEgey50YWJzZXR9CgojIyMgbm90ZXMgCgpVc2VkIFt0aGlzIHBvc3RdKGh0dHA6Ly9kb2luZ2JheWVzaWFuZGF0YWFuYWx5c2lzLmJsb2dzcG90LmNvbS8yMDEyLzA2L2JldGEtZGlzdHJpYnV0aW9uLXBhcmFtZXRlcml6ZWQtYnktbW9kZS5odG1sKSB0byBndWlkZSB0aGlzLiBwYXJ0aWN1bGFybHk6Cgo+PkZvciBhIGJldGEgZGlzdHJpYnV0aW9uIHdpdGggc2hhcGUgcGFyYW1ldGVycyBhIGFuZCBiLCB0aGUgbW9kZSBpcyAoYS0xKS8oYStiLTIpLiBTdXBwb3NlIHdlIGhhdmUgYSBkZXNpcmVkIG1vZGUsIGFuZCB3ZSB3YW50IHRvIGRldGVybWluZSB0aGUgY29ycmVzcG9uZGluZyBzaGFwZSBwYXJhbWV0ZXJzLiBIZXJlJ3MgdGhlIHNvbHV0aW9uLiBGaXJzdCwgd2UgZXhwcmVzcyB0aGUgImNlcnRhaW50eSIgb2YgdGhlIGVzdGltYXRlIGluIHRlcm1zIG9mIHRoZSBlcXVpdmFsZW50IHByaW9yIHNhbXBsZSBzaXplLAprPWErYiwgd2l0aCBr4omlMi4gClRoZSBjZXJ0YWludHkgbXVzdCBiZSBhdCBsZWFzdCAyIGJlY2F1c2UgaXQgZXNzZW50aWFsbHkgYXNzdW1lcyB0aGF0IHRoZSBwcmlvciBjb250YWlucyBhdCBsZWFzdCBvbmUgImhlYWQiIGFuZCBvbmUgInRhaWwsIiB3aGljaCBpcyB0byBzYXkgdGhhdCB3ZSBrbm93IGVhY2ggb3V0Y29tZSBpcyBhdCBsZWFzdCBwb3NzaWJsZS4gVGhlbiBhIGxpdHRsZSBhbGdlYnJhIHJldmVhbHM6CmEgPSBtb2RlICogKGstMikgKyAxCmIgPSAoMS1tb2RlKSAqIChrLTIpICsgMQoKCgojIyMgc2hhcGUgMSBhcyBtb2RlIHdpdGggdiBhbmQgYmV0YSBhcyBiZXRhIHNoYXBlIHBhcmFtZXRlcnMgCgpGb3IgdGhpcyB2ZXJzaW9uIHdlIHRyeSBhbmQgZXN0aW1hdGUgdGhlICdtb2RlJyB0byBiZSBzaGFwZSAxLiBLSVJTVElOOjogZXhwbGFpbiBoZXJlCgojIyMgTW9kZWwKCmRvZXNudCB3b3JrLCBzbyBza2lwIHRoaXMgZmlyc3QgYXR0ZW1wdAoKYGBge3IgbW9kZSAxIHNldCB1cH0KI3NjcmlwdApzdGFubmFtZT0nYmV0YV9tb2RlX1JMLnN0YW4nCgpgYGAKCgpgYGB7ciBtb2RlIDF9CgpmbGFyZV9maXQgPC0gbW9kZWxfcnVuKCdza2lwJyxzdGFubmFtZSxmbGFyZV9kYXRhX25vbG9nKQoKIyMgZ2V0IHNvbWUgYmFzaWMgb3V0cHV0IGRlc2NyaXB0aW9ucyBwcmludGVkIHRvIHNjcmVlbgpvdXRfZGVzY3JpYmUoZmxhcmVfZml0LG5zdWIpCgojIGV4dHJhY3QgZml0IGRhdGEKc3VtbWFyeV9mbGFyZSA8LSBzdW1tYXJ5KGZsYXJlX2ZpdCkKCmBgYAoKIyMjIHYgYXMgbW9kZQoKRm9yIHRoaXMgdmVyc2lvbiB3ZSBhc3N1bWUgdGhhdCBWIGlzIHRoZSBtb2RlIChhYm92ZSB3ZSBhc3N1bWVkIGl0IHNlcnZlcyBhcyB0aGUgbWVhbikgYW5kIGJldGEgaXMgdGhlIGNlcnRhaW50eSBhc3BlY3QgKGkuZS4gaykKCldoYXQgdGhpcyBkb2VzIGlzIGJhc2ljYWxseSB0cmVhdCB0aGUgZXhwZWN0ZWQgcmF0aW5nICh2YWx1ZSkgYXMgdGhlIGEgcGFyYW1ldGVyIGZvciB0aGUgZGlzdHJpYnV0aW9uIChzY2FsZWQgYnkgdGhlaXIgY2VydGFpbml0eSAtIGJldGEpIGFuZCAxLXRoYXQgdmFsdWUgYXMgdGhlIGIgcGFyYW1ldGVyIChhZ2Fpbiwgc2NhbGVkIGJ5IHRoZSB1bmNlcnRhaW50eSkuIAoKc28geW91IGhhdmUgYSByYXRpbyBvZiB0aGVpciBzZWxlY3RlZCB2YWx1ZSBwZXIgdHJpYWwgKG1vZGUgYWNyb3NzIGl0ZXJhdGlvbnM/KSB0byBob3cgZmFyIGZyb20gdGhlIGhpZ2hlc3QgcG9zc2libGUgY2hvaWNlIHRoZXkgYXJlLgoKIyMjIE1vZGVsCgpgYGB7ciBtb2RlIDIgc2V0IHVwfQojc2NyaXB0CnN0YW5uYW1lPSdiZXRhX21vZGVfUkxfMi5zdGFuJwoKYGBgCgoKYGBge3IgbW9kZSAyfQoKZmxhcmVfZml0IDwtIG1vZGVsX3J1bignbWVkJyxzdGFubmFtZSxmbGFyZV9kYXRhKQoKIyMgZ2V0IHNvbWUgYmFzaWMgb3V0cHV0IGRlc2NyaXB0aW9ucyBwcmludGVkIHRvIHNjcmVlbgpvdXRfZGVzY3JpYmUoZmxhcmVfZml0LG5zdWIpCgojIGV4dHJhY3QgZml0IGRhdGEKc3VtbWFyeV9mbGFyZSA8LSBzdW1tYXJ5KGZsYXJlX2ZpdCkKCmBgYAoKClRoaXMgd29ya3MsIGJ1dCB0aGVyZSBpcyBub3QgYSBsb3Qgb2YgdmFyaWFuY2UgaW4gdGhlIGFscGhhIHBhcmFtZXRlciB3aGVuIGRlc2NyaWJlZCBieSBtb2RlIG1lYW4gMC40OTsgc2QgPSAwLjA2LiBDb21wYXJlZCB0byBkZWZpbmVkIGJ5IG1lYW4gd2hlcmUgbWVhbiBpcyAwLjU0IGFuZCBzZCBpcyAwLjI2LgoKSG93ZXZlciB0aGVyZSBpcyBhIGxvdCBvZiB2YXJpYXRpb24gaW4gdGhlIGJldGEgcGFyYW1ldGVyIChtZWFuIC03LjIxLCBzZCA9IDEzNC43NCkKCiMjIyMgQ3JlYXRlIEJJQyBmcm9tIGxvZyBsaWtlbGlob29kCgpgYGB7cn0KIyMgZXh0cmFjdCBsb2cgbGlrZWxpaG9vZAoKZmxhcmVfbG9nbGlrZSA8LSBleHRyYWN0X2xvZ19saWsoZmxhcmVfZml0LCBwYXJhbWV0ZXJfbmFtZSA9ICJsb2dsaWsiLCBtZXJnZV9jaGFpbnMgPSBUUlVFKQoKI2NhbGN1bGF0ZSBCSUMKCkZMQVJlX2JpYzwtYmljKG50cmlhbHMsLWNvbE1lYW5zKGZsYXJlX2xvZ2xpa2UpLDIpICNudW1iZXIgb2YgcGFyYW1ldGVycyBpbiB0aGF0IG1vZGVsIGUuZy4gNCkKCiMjIG1lYW4gQklDIGFzIG1vZGVsIGNvbXBhcmlzb25zIHRvb2w6CgpwcmludCgiTWVhbiBCYXllc2lhbiBpbmZvcm1hdGlvbiBjcml0ZXJpb24gZm9yIG1vZGVsIikKbWVhbihGTEFSZV9iaWMpCgpgYGAKCgojIyMjIEFkZCB0byBiYXIgcGxvdAoKYGBge3J9Cgptb2RfY29tcCA8LSByYmluZChtb2RfY29tcCxjKCJNb2RlIDEgYmV0YSIsYXMubnVtZXJpYyhtZWFuKEZMQVJlX2JpYykpKSkKCm1vZF9jb21wJEJJQyA8LSBvZHAoYXMubnVtZXJpYyhtb2RfY29tcCRCSUMpKQoKbW9kX2NvbXAgPC0gYXMuZGF0YS5mcmFtZShuYS5vbWl0KG1vZF9jb21wKSkKCgojIyBwbG90IGZ1bmN0aW9uIC0gY3JlYXRlIHBsb3QKcGxvdF9tb2RlbHMobW9kX2NvbXApCgpgYGAKCgojIyBNb2RlbCA1OiBSTCBtZWFuIGRlZmluZWQsdHdvIGJldGEgey50YWJzZXR9CgojIyMgTW9kZWwKClJMIG1vZGVsIGFkZGluZyBhIGJldGEgcGVyIHN0aW11bHVzIHRvIEFsZXgncyBtb2RlbAoKYGBge3IgbWVhbiAyIGJldGEgc2V0IHVwfQojc2NyaXB0CnN0YW5uYW1lPSdiZXRhX21lYW5zZF8yYmV0YV9STC5zdGFuJwoKYGBgCgoKYGBge3IgbWVhbiAyIGJldGF9CgpmbGFyZV9maXQgPC0gbW9kZWxfcnVuKCdmdWxsJyxzdGFubmFtZSxmbGFyZV9kYXRhKQoKIyMgZ2V0IHNvbWUgYmFzaWMgb3V0cHV0IGRlc2NyaXB0aW9ucyBwcmludGVkIHRvIHNjcmVlbgpvdXRfZGVzY3JpYmUoZmxhcmVfZml0LG5zdWIpCgojIGV4dHJhY3QgZml0IGRhdGEKc3VtbWFyeV9mbGFyZSA8LSBzdW1tYXJ5KGZsYXJlX2ZpdCkKCmBgYAoKIyMjIyBDcmVhdGUgQklDIGZyb20gbG9nIGxpa2VsaWhvb2QKCmBgYHtyIG1lYW4gMiBiZXRhIGJpY30KIyMgZXh0cmFjdCBsb2cgbGlrZWxpaG9vZAoKZmxhcmVfbG9nbGlrZV9tMiA8LSBleHRyYWN0X2xvZ19saWsoZmxhcmVfZml0X20yLCBwYXJhbWV0ZXJfbmFtZSA9ICJsb2dsaWsiLCBtZXJnZV9jaGFpbnMgPSBUUlVFKQoKI2NhbGN1bGF0ZSBCSUMKCkZMQVJlX2JpY19tMiA8LSBiaWMobnRyaWFscywtY29sTWVhbnMoZmxhcmVfbG9nbGlrZV9tMiksMykgI251bWJlciBvZiBwYXJhbWV0ZXJzIGluIHRoYXQgbW9kZWwgZS5nLiA0KQoKIyBtZWFuIGZvciBhbGwgcGFydGljaXBhbnRzCgptZWFuKEZMQVJlX2JpY19tMikKCmBgYAoKCiMjIyMgQWRkIHRvIGJhciBwbG90CgpgYGB7cn0KCm1vZF9jb21wIDwtIHJiaW5kKG1vZF9jb21wLGMoIk1lYW5zIDIgYmV0YSIsbWVhbihGTEFSZV9iaWNfbTIpKSkKCgptb2RfY29tcCRCSUMgPC0gb2RwKGFzLm51bWVyaWMobW9kX2NvbXAkQklDKSkKCm1vZF9jb21wIDwtIGFzLmRhdGEuZnJhbWUobmEub21pdChtb2RfY29tcCkpCgoKIyMgcGxvdCBmdW5jdGlvbiAtIGNyZWF0ZSBwbG90CnBsb3RfbW9kZWxzKG1vZF9jb21wKQoKYGBgCgoKIyMgTW9kZWwgNjogUkwgbW9kZSBkZWZpbmVkLHR3byBiZXRhIHsudGFic2V0fQoKIyMjIE1vZGVsClJMIG1vZGVsIGFkZGluZyBhIGJldGEgcGVyIHN0aW11bGkgdG8gbW9kZWwgZGVmaW5pbmcgdGhlIGJldGEgc2hhcGUgdXNpbmcgdGhlIG1vZGUgaW5zdGVhZCBvZiB0aGUgbWVhbi4gVGhpcyBkZWZpbml0ZWx5IG1ha2VzIG1vcmUgc2Vuc2UgYXMgd2UgYXNzdW1lIHRoYXQgdGhleSB3aWxsIGhhdmUgZGlmZmVyZW50IGxldmVscyBvZiB1bmNlcnRhaW50eSBhYm91dCBlYWNoLiAKCgpgYGB7ciBtb2RlIDIgYmV0YSBzZXQgdXB9CiNzY3JpcHQKc3Rhbm5hbWU9J2JldGFfbW9kZV8yYmV0YV9STF8yLnN0YW4nCgpgYGAKCgpgYGB7ciBtb2RlIDIgYmV0YX0KCmZsYXJlX2ZpdCA8LSBtb2RlbF9ydW4oJ2Z1bGwnLHN0YW5uYW1lLGZsYXJlX2RhdGFfbm9sb2cpCgojIyBnZXQgc29tZSBiYXNpYyBvdXRwdXQgZGVzY3JpcHRpb25zIHByaW50ZWQgdG8gc2NyZWVuCm91dF9kZXNjcmliZShmbGFyZV9maXQsbnN1YikKCiMgZXh0cmFjdCBmaXQgZGF0YQpzdW1tYXJ5X2ZsYXJlIDwtIHN1bW1hcnkoZmxhcmVfZml0KQoKYGBgCgoKVGhlIGFscGhhIHBhcmFtZXRlciB2YXJpYW5jZSBpcyBub3JtYWwgKG1lYW4gMC40IGFuZCBzZCAwLjEyKS4gQmV0YSBpcyBtdWNoIG1vcmUgYm91bmRlZCBub3cgdGhvdWdoIChjb21iaW5lZCBhY3Jvc3MgYm90aCBzdGltdWxpIG1lYW4gMC43OSwgc2Q9MS42KSBvdmVyIDQwMDAgaXRlcmF0aW9ucyBvbiA0IGNoYWlucy4KCgojIyMjIENyZWF0ZSBCSUMgZnJvbSBsb2cgbGlrZWxpaG9vZAoKYGBge3J9CiMjIGV4dHJhY3QgbG9nIGxpa2VsaWhvb2QKCmZsYXJlX2xvZ2xpa2UgPC0gZXh0cmFjdF9sb2dfbGlrKGZsYXJlX2ZpdCwgcGFyYW1ldGVyX25hbWUgPSAibG9nbGlrIiwgbWVyZ2VfY2hhaW5zID0gVFJVRSkKCiNjYWxjdWxhdGUgQklDCgpGTEFSZV9iaWM8LWJpYyhudHJpYWxzLC1jb2xNZWFucyhmbGFyZV9sb2dsaWtlKSwyKSAjbnVtYmVyIG9mIHBhcmFtZXRlcnMgaW4gdGhhdCBtb2RlbCBlLmcuIDQpCgojIyBtZWFuIEJJQyBhcyBtb2RlbCBjb21wYXJpc29ucyB0b29sOgoKcHJpbnQoIk1lYW4gQmF5ZXNpYW4gaW5mb3JtYXRpb24gY3JpdGVyaW9uIGZvciBtb2RlbCIpCm1lYW4oRkxBUmVfYmljKQoKYGBgCgojIyMjIEFkZCB0byBiYXIgcGxvdAoKYGBge3J9Cgptb2RfY29tcCA8LSByYmluZChuYS5vbWl0KG1vZF9jb21wKSxjKCJNb2RlIDIgYmV0YSIsbWVhbihGTEFSZV9iaWMpKSkKCm1vZF9jb21wJEJJQyA8LSBvZHAoYXMubnVtZXJpYyhtb2RfY29tcCRCSUMpKQoKbW9kX2NvbXAgPC0gYXMuZGF0YS5mcmFtZShuYS5vbWl0KG1vZF9jb21wKSkKCgojIyBwbG90IGZ1bmN0aW9uIC0gY3JlYXRlIHBsb3QKcGxvdF9tb2RlbHMobW9kX2NvbXApCgpgYGAKCiMjIE1vZGVsIDc6IFJMIG1lYW4gZGVmaW5lZCwgbm8gYmV0YSB7LnRhYnNldH0KCiMjIyBNb2RlbAoKVGhlIGJldGEgZG9lc250IHdvcmsgYXMgd2VsbCBmb3IgdGhlIENTKyBzdGltdWx1cywgbmVlZCB0byBjaGVjayBpZiB0aGlzIHBhcmFtZXRlciBhZGRzIGFueXRoaW5nIHRvIHRoZSBtb2RlbCAtIGRyb3AgaXQgZnJvbSBvdXIgYmVzdCBtZWFuIG1vZGVsIGFuZCBzZWUgaG93IHRoaXMgY2hhbmdlcyB0aGUgZml0LgoKdGhpcyB0YWtlcyBmb3IgZXZlciB0byBydW4gYW5kIHRoZSBsb2dsaWtsaWhvb2QgZmFpbHMuIFNvIG5vIGlkZWEgaWYgaXQgaXMgZ29vZCB5ZXQgLSBjb21lIGJhY2sgdG8gdGhpcy4gKioqc2tpcHBlZCBmb3Igbm93KioqCgoKYGBge3IgbWVhbiBOTyBiZXRhIHNldCB1cH0KI3NjcmlwdApzdGFubmFtZT0nYmV0YV9tZWFuc2RfUkxfTm9CZXRhLnN0YW4nCgpgYGAKCgpgYGB7ciBtZWFuIE5vIGJldGF9CgpmbGFyZV9maXQgPC0gbW9kZWxfcnVuKCdza2lwJyxzdGFubmFtZSxmbGFyZV9kYXRhX25vbG9nKQoKIyMgZ2V0IHNvbWUgYmFzaWMgb3V0cHV0IGRlc2NyaXB0aW9ucyBwcmludGVkIHRvIHNjcmVlbgpvdXRfZGVzY3JpYmUoZmxhcmVfZml0LG5zdWIpCgojIGV4dHJhY3QgZml0IGRhdGEKc3VtbWFyeV9mbGFyZSA8LSBzdW1tYXJ5KGZsYXJlX2ZpdCkKCmBgYAoKCiMjIyMgQ3JlYXRlIEJJQyBmcm9tIGxvZyBsaWtlbGlob29kCgpgYGB7cn0KIyAKIyAjIyBleHRyYWN0IGxvZyBsaWtlbGlob29kCiMgCiMgZmxhcmVfbG9nbGlrZSA8LSBleHRyYWN0X2xvZ19saWsoZmxhcmVfZml0LCBwYXJhbWV0ZXJfbmFtZSA9ICJsb2dsaWsiLCBtZXJnZV9jaGFpbnMgPSBUUlVFKQojIAojICNjYWxjdWxhdGUgQklDCiMgCiMgRkxBUmVfYmljPC1iaWMobnRyaWFscywtY29sTWVhbnMoZmxhcmVfbG9nbGlrZSksMikgI251bWJlciBvZiBwYXJhbWV0ZXJzIGluIHRoYXQgbW9kZWwgZS5nLiA0KQojIAojICMjIG1lYW4gQklDIGFzIG1vZGVsIGNvbXBhcmlzb25zIHRvb2w6CiMgCiMgcHJpbnQoIk1lYW4gQmF5ZXNpYW4gaW5mb3JtYXRpb24gY3JpdGVyaW9uIGZvciBtb2RlbCIpCiMgbWVhbihGTEFSZV9iaWMpCgpgYGAKCiMjIyMgQWRkIHRvIGJhciBwbG90CgpgYGB7cn0KIyAKIyBtb2RfY29tcCA8LSByYmluZChuYS5vbWl0KG1vZF9jb21wKSxjKCJNZWFuIG5vIGJldGEiLG1lYW4oRkxBUmVfYmljKSkpCiMgCiMgIwojIG1vZF9jb21wJEJJQyA8LSBvZHAoYXMubnVtZXJpYyhtb2RfY29tcCRCSUMpKQojIAojIG1vZF9jb21wIDwtIGFzLmRhdGEuZnJhbWUobmEub21pdChtb2RfY29tcCkpCiMgCiMjIHBsb3QgZnVuY3Rpb24gLSBjcmVhdGUgcGxvdAojIHBsb3RfbW9kZWxzKG1vZF9jb21wKQoKYGBgCgojIEdlbmVyYXRlIGFuZCByZWNvdmVyIAoKSGVyZSBJIHRlc3Qgd2hldGhlciB0aGUgbW9kZWwgaXMgd29ya2luZyB3ZWxsIGJ5IHNlZWluZyBpZiBJIGNhbiB1c2UgdGhlIHBhcmFtZXRlcnMgd2UndmUgZXN0aW1hdGVkIHRvIHRyeSBhbmQgZ2VuZXJhdGUgb3VyIGV4aXN0aW5nIHJhdGluZyBkYXRhIGFuZCB0aGVuIHJlY292ZXIgc2ltaWxhciBwYXJhbWV0ZXJzIGFnYWluLgoKSSB3aWxsIGRvIHRoaXMgZm9yIHRoZSBiZXN0IGZpdHRpbmcgbW9kZWwgKG1lYW4gZGVmaW5lZCBiZXRhIGRpc3RyaWJ1dGlvbiB3aXRoIGEgdmFyaWFuY2UgZXN0aW1hdGUgcGVyIHBlcnNvbiBmb3IgZWFoYyBzdGltdWx1cykgVGhpcyBpcyB0aGUgbW9kZWwgd2hlcmUgd2UgdHJlYXQgdGhlIGl0ZXJhcnRlZCByYXRpbmdzIGFzIGlmIHRoZXkgYXJlICdleHBlY3RlZCcgdmFsdWVzIGFuZCB1c2UgdGhpcyBhcyBzaGFwZSAxIHBhcmFtZXRlciBmb3Igb3VyIGJldGEgZGlzdHJpYnV0aW9uIGF0IGVhY2ggdHJpYWwuIFdlIGhhdmUgYWxsb3dlZCBhIGJldGEgKG9yIHVuY2VydGFpbnR5KSBwYXJhbWV0ZXIgcGVyIHN0aW11bHVzLgoKQSBnb29kIG1vZGVsIHdpbGwgaGF2ZSAqKmEpKiogYSBnb29kIGNvcnJlbGF0aW9uIGJldHdlZW4gcmVhbCBkYXRhIGFuZCB0aGUgZGF0YSBnZW5lcmF0ZWQgYW5kICoqYikqKiBhIGdvb2QgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgcGFyYW1ldGVyIGVzdGltYXRlcyBmcm9tIHRoZSByZWFsIGFuZCBnZW5lcmF0ZWQgZGF0YS4KCldlIGJhc2ljYWxseSB3YW50IHRvIHJlcGxpY2F0ZSBvdXIgc3RhbiBzY3JpcHQsIGJ1dCBpbmF0ZWFkIG9mIGVzdGltYXRpbmcgcGFyYXRtZXJzLCB3ZSB3YW50IHRvIGFzc3VtZSB0aGF0IHdlIGtub3cgd2hhdCB0aGUgcGFyYW1ldGVycyBhcmUgKGkuZS4gdXNlIHRoZSBhbHBoYSBhbmQgYmV0YSdzIHdlIGhhdmUgZXN0aW1hdGVkIHByZXZpb3VzbHkpLgoKKip1cGRhdGUqKjogdHVybnMgb3V0IHNpbmdsZSBiZXRhIGlzIHRoZSBiZXN0IGZpdHRpbmcgbW9kZWwgd2hlbiBJIGNvcnJlY3QgbXkgQklDIGZ1bmN0aW9uIHRvIGluY2x1ZGUgdGhlIG5lZ2F0aXZlIGxvZyBsaWtlbGlob29kLiBTbyB3aWxsIGFsc28gZ2VuZXJhdGUgYW5kIHJlY292ZXIgZm9yIHRoaXMgbW9kZWwgYW5kIHVzZSB0aGlzIGFzIHRoZSBjb21wYXJhdG9yLgoKCiMjIE1lYW4gMSBiZXRhCiMjIyBHZW5lcmF0ZSAKIyMjIyMgTWFrZSBhbHBoYSAvIGJldGEgZGF0YXNldHMgcC9wCgpVc2UgdGhlIHN1bW1hcnkgb2YgdGhlIHN0YW4gbW9kZWwgdG8gZXh0cmFjdCB0aGUgZGlmZmVyZW50IHBhcmFtZXRlcnMgd2Ugd2FudCB0byB0cnkgdG8gdXNlIHRvIHJlY3JlYXRlIG91ciBkYXRhLgoKYGBge3J9CgpwYXJhbXMgPC0gc3VtbWFyeShmbGFyZV9maXRfYmVzdCkKYWxwaGFfZXN0IDwtIGRhdGEuZnJhbWUocGFyYW1zJHN1bW1hcnlbMTpuc3ViLDFdKQpiZXRhIDwtIGRhdGEuZnJhbWUocGFyYW1zJHN1bW1hcnlbKG5zdWIrMSk6KG5zdWIqMiksMV0pCgoKbmFtZXMoYmV0YSkgPC0gImJldGEiCgpgYGAKCiMjIyMjIEluaXRpYWxpc2UgZW1wdHkgZGF0YXNldHMgdG8gaG9sZCB0aGUgcHJlZGljdGVkIHJhdGluZ3MKCmBgYHtyfQoKcmF0aW5nX2VzdF9wbHVzIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9bnRyaWFscyxucm93PW5zdWIpKQpyYXRpbmdfZXN0X21pbnVzIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9bnRyaWFscyxucm93PW5zdWIpKQoKIyBiZXRhIHNoYXBlIHBhcmFtZXRlcnMKc2hhcGUxcCA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPW50cmlhbHMsbnJvdz1uc3ViKSkKc2hhcGUxbSA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPW50cmlhbHMsbnJvdz1uc3ViKSkKc2hhcGUycCA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPW50cmlhbHMsbnJvdz1uc3ViKSkKc2hhcGUybSA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPW50cmlhbHMsbnJvdz1uc3ViKSkKCiMgViBwYXJhbWV0ZXJzIChpbml0aWFsaXNlZCBhdCAwLjUpCnZwIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9bnRyaWFscyxucm93PW5zdWIpKQp2bSA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPW50cmlhbHMsbnJvdz1uc3ViKSkKCnZwWzFdIDwtIDAuNQp2bVsxXSA8LSAwLjUKCiMgcHJlZGljdGlvbiBlcnJvciAKCmRwIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9KG50cmlhbHMtMSksbnJvdz1uc3ViKSkgCmRtIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9KG50cmlhbHMtMSksbnJvdz1uc3ViKSkgCgogIApgYGAKCiMjIyMjIFNpbXVsYXRlIHJhdGluZ3MKClVzZSBvdXIgZXh0cmFjdGVkIHBhcmFtZXRlcnMgaW4gcGxhY2Ugb2YgZXN0aW1hdGluZyB0aGUgc2FtZS4gVXNlIHRoZSBzdGFuIHN5bnRheAoKCiMjIyMjIyAgUG9wdWxhdGUgb3VyIHZwbHVzIGFuZCBkZWx0YSBmcmFtZXMKCnVzZSB0aGUgYWxwaGEgcGFyYW1ldGVycyB3ZSd2ZSBleHRyYWN0ZWQgKGFscGhhX2VzdCkKZCA9PSBkZWx0YSAocHJlY2RpY3Rpb24gZXJyb3IpCnYgPT0gdmFsdWUgKGkuZS4gdmFsdWUgZm9yIGVhY2ggc3RpbXVsdXMpCgoKYGBge3J9Cgpmb3IgKHAgaW4gMTpuc3ViKXsKICBmb3IgKHQgaW4gMToobnRyaWFscy0xKSl7CiAgICAgIGRwW3AsdF0gPC0gc2NyZWFtUGx1c1twLHRdLXZwW3AsdF0KICAgICAgZG1bcCx0XSA8LSBzY3JlYW1NaW51c1twLHRdLXZtW3AsdF0KICAgICAgdnBbcCx0KzFdIDwtIHZwW3AsdF0rYWxwaGFfZXN0W3AsMV0qZHBbcCx0XQogICAgICB2bVtwLHQrMV08LSB2bVtwLHRdK2FscGhhX2VzdFtwLDFdKmRtW3AsdF0KICAgIH0KfQoKYGBgCgogICAgZm9yICh0IGluIDE6bnRyaWFscyl7CiAgICAgIHNoYXBlMV9QbHVzW3QscF0gPSBWUGx1c1t0LHBdICogKChWUGx1c1t0LHBdICogKDEtVlBsdXNbdCxwXSkpIC8gYmV0YVtwLDFdKTsKICAgICAgc2hhcGUxX01pbnVzW3QscF0gPSBWTWludXNbdCxwXSAqICgoVk1pbnVzW3QscF0gKiAoMS1WTWludXNbdCxwXSkpIC8gYmV0YVtwLDJdKTsKICAgICAgc2hhcGUyX1BsdXNbdCxwXSA9ICgxLVZQbHVzW3QscF0pICogKChWUGx1c1t0LHBdICogKDEtVlBsdXNbdCxwXSkpIC8gYmV0YVtwLDFdKTsKICAgICAgc2hhcGUyX01pbnVzW3QscF0gPSAoMS1WTWludXNbdCxwXSkgKiAoKFZNaW51c1t0LHBdICogKDEtVk1pbnVzW3QscF0pKSAvIGJldGFbcCwyXSk7CgogICAgICByYXRpbmdzUGx1c1t0LHBdIH4gYmV0YShzaGFwZTFfUGx1c1t0LHBdLHNoYXBlMl9QbHVzW3QscF0pOwogICAgICByYXRpbmdzTWludXNbdCxwXSB+IGJldGEoc2hhcGUxX01pbnVzW3QscF0sc2hhcGUyX01pbnVzW3QscF0pOwogICAgfQogIH0KfQoKCiMjIyMjIyBwb3B1bGF0ZSBiZXRhIHBhcmFtZXRlciBzaGFwZSBmcmFtZXMKClVzZSB0aGUgbmV3IHYgZnJhbWVzIGFuZCBiZXRhIHBhcmFtZXRlcnMuCgpTaGFwZSAxIGFuZCAyIGFyZSBzdWZmaWNpZW50IHBhcmFtZXRlcnMgZm9yIHRoZSBiZXRhIGRpc3RyaWJ1dGlvbgoKYGBge3J9Cgpmb3IgKHAgaW4gMTpuc3ViKXsKICAKICBmb3IgKHQgaW4gMTpudHJpYWxzKXsKICAgIAogICAgICBzaGFwZTFwW3AsdF0gPSB2cFtwLHRdICogKCh2cFtwLHRdICogKDEtdnBbcCx0XSkpIC8gYmV0YVtwLDFdKQogICAgICBzaGFwZTFtW3AsdF0gPSB2bVtwLHRdICogKCh2bVtwLHRdICogKDEtdm1bcCx0XSkpIC8gYmV0YVtwLDFdKQogICAgICBzaGFwZTJwW3AsdF0gPSAoMS12cFtwLHRdKSAqICgodnBbcCx0XSAqICgxLXZwW3AsdF0pKSAvIGJldGFbcCwxXSkKICAgICAgc2hhcGUybVtwLHRdID0gKDEtdm1bcCx0XSkgKiAoKHZtW3AsdF0gKiAoMS12bVtwLHRdKSkgLyBiZXRhW3AsMV0pCiAgICAgIAogIH0KfQogIAoKYGBgCgoKIyMjIyMjIEVzdGltYXRlIHJhdGluZ3MKCgp0cnlpbmcgdG8gdXNlIHBiZXRhIGhlcmUgKGRlcml2ZXMgdGhlIGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiBnaXZlbW4gYSBzZXQgb2YgcHJvYmFiaWxpdGllcykgCgpGb3Igbm93LCBzZXR0aW5nIHByb2JhYmlsaXRpZXMgYmV0d2VlbiAwIGFuZCAxIGFuZCB0YWtpbmcgdGhlIGF2ZXJhZ2UuLi4KYGBge3J9CgoKZm9yIChwIGluIDE6bnN1Yil7CiAgCiAgZm9yICh0IGluIDE6bnRyaWFscyl7CiAgICAKICAgIHJhdGluZ19lc3RfcGx1c1twLHRdIDwtIG1lYW4ocmJldGEoMTAwMCxzaGFwZTFwW3AsdF0sc2hhcGUycFtwLHRdKSkKICAgIHJhdGluZ19lc3RfbWludXNbcCx0XSA8LSBtZWFuKHJiZXRhKDEwMDAsc2hhcGUxbVtwLHRdLHNoYXBlMm1bcCx0XSkpCiAgICAKICB9Cn0KCgpgYGAKCiMjIyMgUmVzY2FsZSBzaW11bGF0ZWQgcmF0aW5ncwoKWW91IGNvdWxkIGFyZ3VlIHRoYXQgdGhlc2Ugc2hvdWxkIG1hdGNoIHRoZSBkaXNjcmV0ZSBzY2FsZSBuYXR1cmUgb2YgdGhlIG9yaWdpbmFsIHJhdGluZ3MuIFdlIGVmZmVjdGl2ZWx5IHVuZGlkIHRoaXMgaW4gb3VyIHNjcmlwdC4gVGhlIGZvbGxvd2luZyB3aWxsIGVuYWJsZSB0aGlzLgoKSE9XRVZFUjogd2UgYXJlIHJlZGN1Y2luZyB2YXJpYW5jZSBtYXNzaXZlbHkgdGhpcyB3YXksIHNvIHRoaW5rIGl0IG1pZ2h0IGJlIGJldHRlciB0byBsZWF2ZSB0aGUgcmVjb3ZlcmVkIHJhdGluZ3MgdW5zY2FsZXMuLi4uCgpTbyAtIHRoZSBmb2xsb3dpbmcgZGlzY3JldGUgdmFsdWVzIGV4aXN0IGluIG91ciByZXNjYWxlZCByYXRpbmdzOgpgYGB7cn0KCnRhYmxlKHBsdXNfc2NhbGVkJFgxKQoKYGBgCgpXaWxsIG1ha2UgaXQgdGhhdCBhbnl0aGluZyB0aGF0IGZhbGxzIDAuMDU1NTU1NTYgYWJvdmUgb3IgYmVsb3cgb25lIG9mIHRoZXNlIHZhbHVlcyBpcyBzZXQgdG8gdGhpcyBtZWRpYW4gcG9pbnQuIE5vdGUgdGhhdCB0aGlzIGlzIG91ciBjZGZfc2NhbGUgZmFjdG9yIHRoYXQgd2UgdXNlZCBpbiB0aGUgc2NyaXB0IHRvIGNhcHR1cmUgdGhlIGZ1bGwgYXJlYSB1bmRlciB0aGUgY3VydmUgZm9yIGVhY2ggc2VnbWVudCBvZiB0aGUgZGlzdHJpYnV0aW9uIHJlcHJlc2VudGVkIGJ5IHRoZSBkaXNjcmV0ZSByYXRpbmdzIG9mIDEtOS4KCldyaXRlIHRoZSBmdW5jdGlvbiB0byByZXNjYWxlCgpgYGB7cn0KCgpzY2FsZV9zaW11bGF0ZWQgPC0gZnVuY3Rpb24oeCl7CiAgCiAgc2NhbGVkX2xpc3QgPC0gYXJyYXkodW5pcXVlKHBsdXNfc2NhbGVkJFgxKSkKICAKICBmb3IgKHZhbCBpbiBzY2FsZWRfbGlzdFsxOmxlbmd0aChzY2FsZWRfbGlzdCldKXsKICAgIGlmICh4ID4gdmFsLWNkZl9zY2FsZSAmIHggPCB2YWwrY2RmX3NjYWxlKXsKICAgICAgCiAgICAgIHggPC0gdmFsCiAgICB9CiAgfQogIHJldHVybih4KQp9CgpgYGAKCmFwcGx5IGl0IHRvIHRoZSBzaW11bGF0ZWQgcmF0aW5nIGZyYW1lcy4KCih1bmhhc2ggdG8gcnVuIHRoaXMpCgpgYGB7cn0KIyMgaW5pdGlhbGlzZSBkYXRhZnJhbWVzCiMgCiMgZXN0X3BsdXNfc2NhbGVkIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9ZGltKHJhdGluZ19lc3RfcGx1cylbMl0sbnJvdyA9IGRpbShyYXRpbmdfZXN0X3BsdXMpWzFdKSkKIyBlc3RfbWludXNfc2NhbGVkIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9ZGltKHJhdGluZ19lc3RfbWludXMpWzJdLG5yb3cgPSBkaW0ocmF0aW5nX2VzdF9taW51cylbMV0pKQojIAojICMjICBwb3B1bGF0ZSB3aXRoIHJlc2NhbGVkIHZhbHVlcwojIAojIGZvciAoc3ViIGluIDE6ZGltKHJhdGluZ19lc3RfcGx1cylbMV0pewojICAgZm9yIChjb2wgaW4gMTpkaW0ocmF0aW5nX2VzdF9wbHVzKVsyXSl7CiMgICAgIAojICAgICBlc3RfcGx1c19zY2FsZWRbc3ViLGNvbF0gPC0gc2NhbGVfc2ltdWxhdGVkKHJhdGluZ19lc3RfcGx1c1tzdWIsY29sXSkKIyAgIH0KIyB9CiMgCiMgZm9yIChzdWIgaW4gMTpkaW0ocmF0aW5nX2VzdF9taW51cylbMV0pewojICAgZm9yIChjb2wgaW4gMTpkaW0ocmF0aW5nX2VzdF9taW51cylbMl0pewojICAgICAKIyAgICAgZXN0X21pbnVzX3NjYWxlZFtzdWIsY29sXSA8LSBzY2FsZV9zaW11bGF0ZWQocmF0aW5nX2VzdF9taW51c1tzdWIsY29sXSkKIyAgIH0KIyB9CgoKYGBgCgojIyMjIENvcnJlbGF0ZSBhY3R1YWwgcmF0aW5ncyB3aXRoIHNpbXVsYXRlZCByYXRpbmdzCgp1c2UgdGhlIHNpbXVsYXRlZCByYXRpbmdzIHBlciBwZXJzb24gdGhhdCB3ZSBoYXZlIGRlcml2ZWQgdXNpbmcgb3VyIHBhcmFtZXRlcnMgYW5kIHNlZSBob3cgd2VsbCB0aGV5IGFsaWduIHdpdGggdGhlIHJlYWwgcmF0aW5ncy4uLgoKT25seSBzaG93aW5nIHRoZSBkaWFnYW5vbHMgZnJvbSBjb3JyLnRlc3QgcGFja2FnZSBoZXJlIHRvIGdldCB0aGUgaW1wb3J0YW50IHQxIHggdDEgZXRjIHZhbHVlcy4KCnRoaXMgd2lsbCBiZSB1c2luZyBlaXRoZXIgcmF0aW5nX2VzdCBmaWxlcyAocmF0aW5nX2VzdF9wbHVzO3JhdGluZ19lc3RfbWludXMpIG9yIHRoZSBlc3Rfc2NhbGVkIGZpbGVzIChlc3RfbWludXNfc2NhbGVkOyBlc3RfcGx1c19zY2FsZWQpIGRlcGVuZGluZyBvbiB3aGV0aGVyIHdlIG9wdCB0byByZXR1cm4gc2NhbGluZyBvciBubyAKCmBgYHtyfQoKcHJpbnQoInJlYWwgcmF0aW5ncyB3aXRoIGVzdGltYXRlZCByYXRpbmdzOiBDUyBNSU5VUyIpCmRpYWcoY29yci50ZXN0KHJhdGluZ19lc3RfbWludXMsbWludXNfc2NhbGVkKSRyKQoKcHJpbnQoInJlYWwgcmF0aW5ncyB3aXRoIGVzdGltYXRlZCByYXRpbmdzOiBDUyBNSU5VUyAoYXZlcmFnZSBmb3IgYWxsIHRyaWFscykiKQpjb3Iocm93TWVhbnMocmF0aW5nX2VzdF9taW51cykscm93TWVhbnMobWludXNfc2NhbGVkKSkKCgpwcmludCgicmVhbCByYXRpbmdzIHdpdGggZXN0aW1hdGVkIHJhdGluZ3M6IENTIFBMVVMiKQpkaWFnKGNvcnIudGVzdChyYXRpbmdfZXN0X3BsdXMscGx1c19zY2FsZWQpJHIpCgpwcmludCgicmVhbCByYXRpbmdzIHdpdGggZXN0aW1hdGVkIHJhdGluZ3M6IENTIFBMVVMgKGF2ZXJhZ2UgZm9yIGFsbCB0cmlhbHMpIikKY29yKHJvd01lYW5zKHJhdGluZ19lc3RfcGx1cykscm93TWVhbnMocGx1c19zY2FsZWQpKQoKYGBgCgojIyMgUmVjb3ZlcgoKSGVyZSB3ZSBhcmUgc2VlaW5nIGlmIHdlIGNhbiByZWNvdmVyIHRoZSBzYW1lIGVzdGltYXRlcyB1c2luZyB0aGUgc2ltdWxhdGVkIHJhdGluZ3MuIEJhc2ljYWxseSBydW4gc3RhbiBidXQgdXNpbmcgdGhlIGVzdGltYXRlZCByYXRpbmdzIGluc3RlYWQgb2YgdGhlIHJlYWwgb25lcy4gU2VlIGlmIHdlIGdldCB0aGUgc2FtZSBhbHBoYSAvIGJldGEgcGFyYW1ldGVycy4KCldlIG1pZ2h0IGRlY2lkZSB0byB1c2UgdGhlIHJlc2NhbGVkIGVzdGltYXRlcyBoZXJlIHRvIGJlIG1vcmUgY29tcGFyYWJsZS4uLgoKIyMjIyBydW4gc3RhbiBtb2RlbAoKUkwgbW9kZWwgYWRkaW5nIGEgYmV0YSBwZXIgc3RpbXVsdXMgdG8gQWxleCdzIG1vZGVsCgoKYGBge3IgbWVhbiByZWNvdmVyIHNldCB1cH0KI3NjcmlwdApzdGFubmFtZT0nYmV0YV9tZWFuc2RfUkxfNC5zdGFuJwoKIyBkYXRhIApmbGFyZV9kYXRhX3JlYyA8LWxpc3QobnRyaWFscz1udHJpYWxzLG5zdWI9bnN1YixzY3JlYW1QbHVzID0gdChzY3JlYW1QbHVzKSwgc2NyZWFtTWludXM9IHQoc2NyZWFtTWludXMpLHJhdGluZ3NQbHVzPXQocmF0aW5nX2VzdF9wbHVzKSxyYXRpbmdzTWludXM9dChyYXRpbmdfZXN0X21pbnVzKSxjZGZfc2NhbGU9Y2RmX3NjYWxlKQoKCmBgYAoKCmBgYHtyIG1lYW4gcmVjb3Zlcn0KCmZsYXJlX2ZpdF9yZWMgPC0gbW9kZWxfcnVuKCdmdWxsJyxzdGFubmFtZSxmbGFyZV9kYXRhX3JlYykKCiMjIGdldCBzb21lIGJhc2ljIG91dHB1dCBkZXNjcmlwdGlvbnMgcHJpbnRlZCB0byBzY3JlZW4Kb3V0X2Rlc2NyaWJlKGZsYXJlX2ZpdF9yZWMsbnN1YikKCmBgYAoKCiMjIyMgTWFrZSBhbHBoYSAvIGJldGEgZGF0YXNldHMgcC9wCgpVc2UgdGhlIHN1bW1hcnkgb2YgdGhlIHN0YW4gbW9kZWwgdG8gZXh0cmFjdCB0aGUgZGlmZmVyZW50IHBhcmFtZXRlcnMgd2Ugd2FudCB0byB0cnkgdG8gdXNlIHRvIHJlY3JlYXRlIG91ciBkYXRhLgoKYGBge3J9CgpwYXJhbXNfcmVjIDwtIHN1bW1hcnkoZmxhcmVfZml0X3JlYykKYWxwaGFfZXN0X3JlYyA8LSBkYXRhLmZyYW1lKHBhcmFtc19yZWMkc3VtbWFyeVsxOm5zdWIsMV0pCmJldGFfcmVjIDwtIGRhdGEuZnJhbWUocGFyYW1zX3JlYyRzdW1tYXJ5Wyhuc3ViKzEpOihuc3ViKjIpXSkKCm5hbWVzKGJldGFfcmVjKSA8LSAiYmV0YV9yZWMiCgoKCmBgYAoKIyMjIyBDb3JyZWxhdGUgYWN0dWFsIHJhdGluZ3Mgd2l0aCBzaW11bGF0ZWQgcmF0aW5ncwoKdXNlIHRoZSBzaW11bGF0ZWQgcmF0aW5ncyBwZXIgcGVyc29uIHRoYXQgd2UgaGF2ZSBkZXJpdmVkIHVzaW5nIG91ciBwYXJhbWV0ZXJzIGFuZCBzZWUgaG93IHdlbGwgdGhleSBhbGlnbiB3aXRoIHRoZSByZWFsIHJhdGluZ3MuLi4KCk9ubHkgc2hvd2luZyB0aGUgZGlhZ2Fub2xzIGZyb20gY29yci50ZXN0IHBhY2thZ2UgaGVyZSB0byBnZXQgdGhlIGltcG9ydGFudCB0MSB4IHQxIGV0YyB2YWx1ZXMuCgpgYGB7cn0KCnByaW50KCJvcmlnaW5hbCB3aXRoIHJlY292ZXJlZDogQUxQSEEiKQpkaWFnKGNvcnIudGVzdChhbHBoYV9lc3RfcmVjLGFscGhhX2VzdCkkcikKCnByaW50KCJvcmlnaW5hbCB3aXRoIHJlY292ZXJlZDogQkVUQSIpCmRpYWcoY29yci50ZXN0KGJldGFfcmVjLGJldGEpJHIpCgoKCmBgYAoKCiMjIE1lYW4gMiBiZXRhCiMjIyBHZW5lcmF0ZSAKIyMjIyMgTWFrZSBhbHBoYSAvIGJldGEgZGF0YXNldHMgcC9wCgpVc2UgdGhlIHN1bW1hcnkgb2YgdGhlIHN0YW4gbW9kZWwgdG8gZXh0cmFjdCB0aGUgZGlmZmVyZW50IHBhcmFtZXRlcnMgd2Ugd2FudCB0byB0cnkgdG8gdXNlIHRvIHJlY3JlYXRlIG91ciBkYXRhLgoKYGBge3J9CgpwYXJhbXMgPC0gc3VtbWFyeShmbGFyZV9maXRfbTIpCmFscGhhX2VzdCA8LSBkYXRhLmZyYW1lKHBhcmFtcyRzdW1tYXJ5WzE6bnN1YiwxXSkKYmV0YV9wbHVzIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2wgPSAxLG5yb3c9bnN1YikpCmJldGFfbWludXMgPC0gZGF0YS5mcmFtZShtYXRyaXgobmNvbCA9IDEsbnJvdz1uc3ViKSkKCm5hbWVzKGJldGFfcGx1cykgPC0gImJldGFfcGx1cyIKbmFtZXMoYmV0YV9taW51cykgPC0gImJldGFfbWludXMiCiAgCnN1YnAgPSAwCnN1Ym0gPSAwCiAgZm9yICggaSBpbiAzNDM6MTAyNil7CiAgICAKICAgIGlmIChpJSUyID09IDEpewogICAgICBzdWJwPSBzdWJwKzEKICAgICAgYmV0YV9wbHVzW3N1YnAsMV0gPC0gcGFyYW1zJHN1bW1hcnlbaSwxXQogICAgfSBlbHNlIGlmIChpJSUyID09IDApIHsKICAgICAgc3VibT0gc3VibSsxCiAgICAgIGJldGFfbWludXNbc3VibSwxXSA8LSBwYXJhbXMkc3VtbWFyeVtpLDFdIAogICAgfQogICAgCn0KCgpgYGAKCiMjIyMjIEluaXRpYWxpc2UgZW1wdHkgZGF0YXNldHMgdG8gaG9sZCB0aGUgcHJlZGljdGVkIHJhdGluZ3MKCmBgYHtyfQoKcmF0aW5nX2VzdF9wbHVzIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9bnRyaWFscyxucm93PW5zdWIpKQpyYXRpbmdfZXN0X21pbnVzIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9bnRyaWFscyxucm93PW5zdWIpKQoKIyBiZXRhIHNoYXBlIHBhcmFtZXRlcnMKc2hhcGUxcCA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPW50cmlhbHMsbnJvdz1uc3ViKSkKc2hhcGUxbSA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPW50cmlhbHMsbnJvdz1uc3ViKSkKc2hhcGUycCA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPW50cmlhbHMsbnJvdz1uc3ViKSkKc2hhcGUybSA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPW50cmlhbHMsbnJvdz1uc3ViKSkKCiMgViBwYXJhbWV0ZXJzIChpbml0aWFsaXNlZCBhdCAwLjUpCnZwIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9bnRyaWFscyxucm93PW5zdWIpKQp2bSA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPW50cmlhbHMsbnJvdz1uc3ViKSkKCnZwWzFdIDwtIDAuNQp2bVsxXSA8LSAwLjUKCiMgcHJlZGljdGlvbiBlcnJvciAKCmRwIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9KG50cmlhbHMtMSksbnJvdz1uc3ViKSkgCmRtIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9KG50cmlhbHMtMSksbnJvdz1uc3ViKSkgCgogIApgYGAKCiMjIyMjIFNpbXVsYXRlIHJhdGluZ3MKClVzZSBvdXIgZXh0cmFjdGVkIHBhcmFtZXRlcnMgaW4gcGxhY2Ugb2YgZXN0aW1hdGluZyB0aGUgc2FtZS4gVXNlIHRoZSBzdGFuIHN5bnRheAoKCiMjIyMjIyAgUG9wdWxhdGUgb3VyIHZwbHVzIGFuZCBkZWx0YSBmcmFtZXMKCnVzZSB0aGUgYWxwaGEgcGFyYW1ldGVycyB3ZSd2ZSBleHRyYWN0ZWQgKGFscGhhX2VzdCkKZCA9PSBkZWx0YSAocHJlY2RpY3Rpb24gZXJyb3IpCnYgPT0gdmFsdWUgKGkuZS4gdmFsdWUgZm9yIGVhY2ggc3RpbXVsdXMpCgoKYGBge3J9Cgpmb3IgKHAgaW4gMTpuc3ViKXsKICBmb3IgKHQgaW4gMToobnRyaWFscy0xKSl7CiAgICAgIGRwW3AsdF0gPC0gc2NyZWFtUGx1c1twLHRdLXZwW3AsdF0KICAgICAgZG1bcCx0XSA8LSBzY3JlYW1NaW51c1twLHRdLXZtW3AsdF0KICAgICAgdnBbcCx0KzFdIDwtIHZwW3AsdF0rYWxwaGFfZXN0W3AsMV0qZHBbcCx0XQogICAgICB2bVtwLHQrMV08LSB2bVtwLHRdK2FscGhhX2VzdFtwLDFdKmRtW3AsdF0KICAgIH0KfQoKYGBgCgogICAgZm9yICh0IGluIDE6bnRyaWFscyl7CiAgICAgIHNoYXBlMV9QbHVzW3QscF0gPSBWUGx1c1t0LHBdICogKChWUGx1c1t0LHBdICogKDEtVlBsdXNbdCxwXSkpIC8gYmV0YVtwLDFdKTsKICAgICAgc2hhcGUxX01pbnVzW3QscF0gPSBWTWludXNbdCxwXSAqICgoVk1pbnVzW3QscF0gKiAoMS1WTWludXNbdCxwXSkpIC8gYmV0YVtwLDJdKTsKICAgICAgc2hhcGUyX1BsdXNbdCxwXSA9ICgxLVZQbHVzW3QscF0pICogKChWUGx1c1t0LHBdICogKDEtVlBsdXNbdCxwXSkpIC8gYmV0YVtwLDFdKTsKICAgICAgc2hhcGUyX01pbnVzW3QscF0gPSAoMS1WTWludXNbdCxwXSkgKiAoKFZNaW51c1t0LHBdICogKDEtVk1pbnVzW3QscF0pKSAvIGJldGFbcCwyXSk7CgogICAgICByYXRpbmdzUGx1c1t0LHBdIH4gYmV0YShzaGFwZTFfUGx1c1t0LHBdLHNoYXBlMl9QbHVzW3QscF0pOwogICAgICByYXRpbmdzTWludXNbdCxwXSB+IGJldGEoc2hhcGUxX01pbnVzW3QscF0sc2hhcGUyX01pbnVzW3QscF0pOwogICAgfQogIH0KfQoKCiMjIyMjIyBwb3B1bGF0ZSBiZXRhIHBhcmFtZXRlciBzaGFwZSBmcmFtZXMKClVzZSB0aGUgbmV3IHYgZnJhbWVzIGFuZCBiZXRhIHBhcmFtZXRlcnMuCgpTaGFwZSAxIGFuZCAyIGFyZSBzdWZmaWNpZW50IHBhcmFtZXRlcnMgZm9yIHRoZSBiZXRhIGRpc3RyaWJ1dGlvbgoKYGBge3J9Cgpmb3IgKHAgaW4gMTpuc3ViKXsKICAKICBmb3IgKHQgaW4gMTpudHJpYWxzKXsKICAgIAogICAgICBzaGFwZTFwW3AsdF0gPSB2cFtwLHRdICogKCh2cFtwLHRdICogKDEtdnBbcCx0XSkpIC8gYmV0YV9wbHVzW3AsMV0pCiAgICAgIHNoYXBlMW1bcCx0XSA9IHZtW3AsdF0gKiAoKHZtW3AsdF0gKiAoMS12bVtwLHRdKSkgLyBiZXRhX21pbnVzW3AsMV0pCiAgICAgIHNoYXBlMnBbcCx0XSA9ICgxLXZwW3AsdF0pICogKCh2cFtwLHRdICogKDEtdnBbcCx0XSkpIC8gYmV0YV9wbHVzW3AsMV0pCiAgICAgIHNoYXBlMm1bcCx0XSA9ICgxLXZtW3AsdF0pICogKCh2bVtwLHRdICogKDEtdm1bcCx0XSkpIC8gYmV0YV9taW51c1twLDFdKQogICAgICAKICB9Cn0KICAKCmBgYAoKCiMjIyMjIyBFc3RpbWF0ZSByYXRpbmdzCgoKdHJ5aW5nIHRvIHVzZSBwYmV0YSBoZXJlIChkZXJpdmVzIHRoZSBkaXN0cmlidXRpb24gZnVuY3Rpb24gZ2l2ZW1uIGEgc2V0IG9mIHByb2JhYmlsaXRpZXMpIAoKRm9yIG5vdywgc2V0dGluZyBwcm9iYWJpbGl0aWVzIGJldHdlZW4gMCBhbmQgMSBhbmQgdGFraW5nIHRoZSBhdmVyYWdlLi4uCmBgYHtyfQoKCmZvciAocCBpbiAxOm5zdWIpewogIAogIGZvciAodCBpbiAxOm50cmlhbHMpewogICAgCiAgICByYXRpbmdfZXN0X3BsdXNbcCx0XSA8LSBtZWFuKHJiZXRhKDEwMDAsc2hhcGUxcFtwLHRdLHNoYXBlMnBbcCx0XSkpCiAgICByYXRpbmdfZXN0X21pbnVzW3AsdF0gPC0gbWVhbihyYmV0YSgxMDAwLHNoYXBlMW1bcCx0XSxzaGFwZTJtW3AsdF0pKQogICAgCiAgfQp9CgoKYGBgCgojIyMjIENvcnJlbGF0ZSBhY3R1YWwgcmF0aW5ncyB3aXRoIHNpbXVsYXRlZCByYXRpbmdzCgp1c2UgdGhlIHNpbXVsYXRlZCByYXRpbmdzIHBlciBwZXJzb24gdGhhdCB3ZSBoYXZlIGRlcml2ZWQgdXNpbmcgb3VyIHBhcmFtZXRlcnMgYW5kIHNlZSBob3cgd2VsbCB0aGV5IGFsaWduIHdpdGggdGhlIHJlYWwgcmF0aW5ncy4uLgoKT25seSBzaG93aW5nIHRoZSBkaWFnYW5vbHMgZnJvbSBjb3JyLnRlc3QgcGFja2FnZSBoZXJlIHRvIGdldCB0aGUgaW1wb3J0YW50IHQxIHggdDEgZXRjIHZhbHVlcy4KCmBgYHtyfQoKcHJpbnQoInJlYWwgcmF0aW5ncyB3aXRoIGVzdGltYXRlZCByYXRpbmdzOiBDUyBNSU5VUyIpCmRpYWcoY29yci50ZXN0KHJhdGluZ19lc3RfbWludXMsbWludXNfc2NhbGVkKSRyKQoKcHJpbnQoInJlYWwgcmF0aW5ncyB3aXRoIGVzdGltYXRlZCByYXRpbmdzOiBDUyBNSU5VUyAoYXZlcmFnZSBmb3IgYWxsIHRyaWFscykiKQpjb3Iocm93TWVhbnMocmF0aW5nX2VzdF9taW51cykscm93TWVhbnMobWludXNfc2NhbGVkKSkKCgpwcmludCgicmVhbCByYXRpbmdzIHdpdGggZXN0aW1hdGVkIHJhdGluZ3M6IENTIFBMVVMiKQpkaWFnKGNvcnIudGVzdChyYXRpbmdfZXN0X3BsdXMscGx1c19zY2FsZWQpJHIpCgpwcmludCgicmVhbCByYXRpbmdzIHdpdGggZXN0aW1hdGVkIHJhdGluZ3M6IENTIFBMVVMgKGF2ZXJhZ2UgZm9yIGFsbCB0cmlhbHMpIikKY29yKHJvd01lYW5zKHJhdGluZ19lc3RfcGx1cykscm93TWVhbnMocGx1c19zY2FsZWQpKQoKCmBgYAoKIyMjIFJlY292ZXIKCkhlcmUgd2UgYXJlIHNlZWluZyBpZiB3ZSBjYW4gcmVjb3ZlciB0aGUgc2FtZSBlc3RpbWF0ZXMgdXNpbmcgdGhlIHNpbXVsYXRlZCByYXRpbmdzLiBCYXNpY2FsbHkgcnVuIHN0YW4gYnV0IHVzaW5nIHRoZSBlc3RpbWF0ZWQgcmF0aW5ncyBpbnN0ZWFkIG9mIHRoZSByZWFsIG9uZXMuIFNlZSBpZiB3ZSBnZXQgdGhlIHNhbWUgYWxwaGEgLyBiZXRhIHBhcmFtZXRlcnMuCgojIyMjIHJlc2NhbGUgdGhlIGVzdGltYXRlZCByYXRpbmdzCgoKcmVzY2FsZSB0aGUgMS05IGV4cGVjdGFuY3kgdmFsdWVzIHRvIGJlIG9uIGEgMC0xIHNjYWxlLgoKc3RhbiBjYW5ub3QgZGVhbCB3aXRoIHRoZSBleHRyZW1lIGxpbWl0IG9mIHRoZSBiZXRhLCBzbyBtYWtlIHRoZSByZXNjYWxlZCBsaW1pdHMganVzdCBhYm92ZSAwIGFuZCBiZWxvdyBvbmUKCk5vdGUgdGhhdCB3aGVuIGEgdmFsdWUgaGFkIHRvIGJlIGltcHV0ZWQgYXMgaXQgd2FzIG1pc3NpbmcgaXQgd2lsbCBub3QgYmUgYW4gaW50ZWdlci4gVGh1cyB0aGUgZnVuY3Rpb24gbmVlZHMgdG8gYWxsb3cgZm9yIHJhbmdlcyBiZXR3ZWVuIHZhbHVlcy4KCmBgYHtyfQojIAojIG1pbnVzX3NjYWxlZF9lc3QgPC0gZGF0YS5mcmFtZShtYXRyaXgobmNvbD1kaW0ocmF0aW5nX2VzdF9taW51cylbMl0sbnJvdyA9IGRpbShyYXRpbmdfZXN0X21pbnVzKVsxXSkpCiMgCiMgIyMgIHBvcHVsYXRlIHdpdGggcmV4Y2FsZWQgdmFsdWVzCiMgCiMgZm9yIChzdWIgaW4gMTpkaW0ocmF0aW5nX2VzdF9taW51cylbMV0pewojICAgZm9yIChjb2wgaW4gMTpkaW0ocmF0aW5nX2VzdF9taW51cylbMl0pewojICAgICAKIyAgICAgbWludXNfc2NhbGVkX2VzdFtzdWIsY29sXSA8LSBzY2FsZV9mbGFyZShyYXRpbmdfZXN0X21pbnVzW3N1Yixjb2xdKQojICAgfQojIH0KIyAKIyAjIyBkaXR0byBmb3IgcGx1cwojIAojIHBsdXNfc2NhbGVkX2VzdCA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPWRpbShyYXRpbmdfZXN0X3BsdXMpWzJdLG5yb3cgPSBkaW0ocmF0aW5nX2VzdF9wbHVzKVsxXSkpCiMgCiMgIyMgIHBvcHVsYXRlIHdpdGggcmV4Y2FsZWQgdmFsdWVzCiMgCiMgZm9yIChzdWIgaW4gMTpkaW0ocmF0aW5nX2VzdF9wbHVzKVsxXSl7CiMgICBmb3IgKGNvbCBpbiAxOmRpbShyYXRpbmdfZXN0X3BsdXMpWzJdKXsKIyAgICAgCiMgICAgIHBsdXNfc2NhbGVkX2VzdFtzdWIsY29sXSA8LSBzY2FsZV9mbGFyZShyYXRpbmdfZXN0X3BsdXNbc3ViLGNvbF0pCiMgICB9CiMgfQojIAoKCmBgYAoKIyMjIyBydW4gc3RhbiBtb2RlbAoKUkwgbW9kZWwgYWRkaW5nIGEgYmV0YSBwZXIgc3RpbXVsdXMgdG8gQWxleCdzIG1vZGVsCgoKYGBge3IgbWVhbiAyIGJldGEgcmVjb3ZlciBzZXQgdXB9CiNzY3JpcHQKc3Rhbm5hbWU9J2JldGFfbWVhbnNkXzJiZXRhX1JMLnN0YW4nCgojIGRhdGEgCmZsYXJlX2RhdGFfcmVjIDwtbGlzdChudHJpYWxzPW50cmlhbHMsbnN1Yj1uc3ViLHNjcmVhbVBsdXMgPSB0KHNjcmVhbVBsdXMpLCBzY3JlYW1NaW51cz0gdChzY3JlYW1NaW51cykscmF0aW5nc1BsdXM9dChyYXRpbmdfZXN0X3BsdXMpLHJhdGluZ3NNaW51cz10KHJhdGluZ19lc3RfbWludXMpLGNkZl9zY2FsZT1jZGZfc2NhbGUpCgoKCmBgYAoKCmBgYHtyIG1lYW4gMiBiZXRhIHJlY292ZXJ9CgpmbGFyZV9maXRfcmVjIDwtIG1vZGVsX3J1bignZnVsbCcsc3Rhbm5hbWUsZmxhcmVfZGF0YV9yZWMpCgojIyBnZXQgc29tZSBiYXNpYyBvdXRwdXQgZGVzY3JpcHRpb25zIHByaW50ZWQgdG8gc2NyZWVuCm91dF9kZXNjcmliZShmbGFyZV9maXRfcmVjLG5zdWIpCgoKYGBgCgoKIyMjIyBNYWtlIGFscGhhIC8gYmV0YSBkYXRhc2V0cyBwL3AKClVzZSB0aGUgc3VtbWFyeSBvZiB0aGUgc3RhbiBtb2RlbCB0byBleHRyYWN0IHRoZSBkaWZmZXJlbnQgcGFyYW1ldGVycyB3ZSB3YW50IHRvIHRyeSB0byB1c2UgdG8gcmVjcmVhdGUgb3VyIGRhdGEuCgpgYGB7cn0KCnBhcmFtc19yZWMgPC0gc3VtbWFyeShmbGFyZV9maXRfcmVjKQphbHBoYV9lc3RfcmVjIDwtIGRhdGEuZnJhbWUocGFyYW1zX3JlYyRzdW1tYXJ5WzE6bnN1YiwxXSkKYmV0YV9wbHVzX3JlYyA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sID0gMSxucm93PW5zdWIpKQpiZXRhX21pbnVzX3JlYyA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sID0gMSxucm93PW5zdWIpKQoKbmFtZXMoYmV0YV9wbHVzX3JlYykgPC0gImJldGFfcGx1cyIKbmFtZXMoYmV0YV9taW51c19yZWMpIDwtICJiZXRhX21pbnVzIgogIApzdWJwID0gMApzdWJtID0gMAogIGZvciAoIGkgaW4gMzQzOjEwMjYpewogICAgCiAgICBpZiAoaSUlMiA9PSAxKXsKICAgICAgc3VicD0gc3VicCsxCiAgICAgIGJldGFfcGx1c19yZWNbc3VicCwxXSA8LSBwYXJhbXNfcmVjJHN1bW1hcnlbaSwxXQogICAgfSBlbHNlIGlmIChpJSUyID09IDApIHsKICAgICAgc3VibT0gc3VibSsxCiAgICAgIGJldGFfbWludXNfcmVjW3N1Ym0sMV0gPC0gcGFyYW1zX3JlYyRzdW1tYXJ5W2ksMV0gCiAgICB9CiAgICAKfQoKCmBgYAoKIyMjIyBDb3JyZWxhdGUgYWN0dWFsIHJhdGluZ3Mgd2l0aCBzaW11bGF0ZWQgcmF0aW5ncwoKdXNlIHRoZSBzaW11bGF0ZWQgcmF0aW5ncyBwZXIgcGVyc29uIHRoYXQgd2UgaGF2ZSBkZXJpdmVkIHVzaW5nIG91ciBwYXJhbWV0ZXJzIGFuZCBzZWUgaG93IHdlbGwgdGhleSBhbGlnbiB3aXRoIHRoZSByZWFsIHJhdGluZ3MuLi4KCk9ubHkgc2hvd2luZyB0aGUgZGlhZ2Fub2xzIGZyb20gY29yci50ZXN0IHBhY2thZ2UgaGVyZSB0byBnZXQgdGhlIGltcG9ydGFudCB0MSB4IHQxIGV0YyB2YWx1ZXMuCgpgYGB7cn0KCnByaW50KCJvcmlnaW5hbCB3aXRoIHJlY292ZXJlZDogQUxQSEEiKQpkaWFnKGNvcnIudGVzdChhbHBoYV9lc3RfcmVjLGFscGhhX2VzdCkkcikKCnByaW50KCJvcmlnaW5hbCB3aXRoIHJlY292ZXJlZDogQkVUQSBQTFVTIikKZGlhZyhjb3JyLnRlc3QoYmV0YV9wbHVzX3JlYyxiZXRhX3BsdXMpJHIpCgpwcmludCgib3JpZ2luYWwgd2l0aCByZWNvdmVyZWQ6IEJFVEEgTUlOVVMiKQpkaWFnKGNvcnIudGVzdChiZXRhX21pbnVzX3JlYyxiZXRhX21pbnVzKSRyKQoKYGBgCgoKIyBFeHBhbmRpbmcgb24gdGhlIGJlc3QgYmFzZSBtb2RlbAoKIyBQb3RlbnRpYWxseSBpbnRlcmVzdGluZyBwYXJhbWV0ZXJzIHRvIGFkZCB0byBiZXN0IGZpdCBtb2RlbAoKIyMgTW9kZWwgODogUHVuaXNobWVudCBzZW5zaXRpdml0eSAKCkhvdyBhdmVyc2l2ZSB0aGV5IGZpbmQgdGhlIHNjcmVhbSByZWluZm9yY2VtZW50LiBNb2RlbGxpbmcgdGhpcyBvbiB0aGUgbG9zcyBhdmVyc2lvbiBwYXJhbWV0ZXIgaW4gW0NoYXJwZW50aWVyIGV0IGFsXShodHRwczovL2YxMDAwLmNvbS93b3JrL2l0ZW0vNjcwNzEzNC9yZXNvdXJjZXMvNTg2NDc3NC9wZGYpIChzZWUgdGhlIGxhc3QgcGFnZSBiZWZvcmUgcmVmZXJlbmNlcyksCgpUaGlzIHdpbGwgYmUgYSBzaW5nbGUgcGFyYW1ldGVyIHBlciBwZXJzb24sIGFuZCByZXByZXNlbnRzIGhvdyBtdWNoIHRoZSBzY3JlYW0gaW5mbHVlbmNlcyB0aGVpciByYXRpbmdzLiAKCkJhc2VkIG9uIHRoZSBwYXBlciwgd2lsbCB0cnkgdGhlIGZvbGxvd2luZyB0byBtb2RlbCB0aGlzIGluIHN0YW4gYnkgaW5jbHVkaW5nIGl0IGluIG91ciB2YWx1ZSBjYWxjcyBmb3IgdGhlIENTKyBhbmQgQ1MtIHJlc3BlY3RpdmVseS4gd2Ugd2lsbCBkbyB0aGlzIGJ5IGxldHRpbmcgaXQgaW5mbHVlbmNlIGhvdyBtdWNoIHRoZWlyIHByZWRpY3Rpb24gZXJyb3IgY2hhbmdlcyBiYXNlZCBvbiB3aGV0aGVyIGEgc2NyZWFtIG9jY3VycmVkIG9yIG5vdC4gVGhlIHByZWRpY3Rpb24gZXJyb3IgaXMgbGF0ZXIgdXNlZCB0byBjaGFuZ2UgdGhlIHZhbHVlIHJhdGluZyBwZXIgc3RpbXVsdXMKCgokJGQoc3RpbXVsdXMsdHJpYWwpID0gc2NyZWFtKlxsYW1iZGEtdihzdGltdWx1cyx0cmlhbC0xKSQkCgp3aGVyZSAKJCRcbGFtYmRhID0gc2Vuc2l0aXZpdHlcXHRvXFxzY3JlYW1zJCQgCgojIyMgTW9kZWwKCmBgYHtyIHB1bmlzaG1lbnQgc2Vuc2l0aXZpdHkgc2V0IHVwfQojc2NyaXB0CnN0YW5uYW1lPSdiZXRhX21lYW4xYmV0YV9QdW5TZW5zLnN0YW4nCgpgYGAKCgpgYGB7ciBwdW5pc2htZW50IHNlbnNpdGl2aXR5fQoKZmxhcmVfZml0IDwtIG1vZGVsX3J1bignZnVsbCcsc3Rhbm5hbWUsZmxhcmVfZGF0YSkKCiMjIGdldCBzb21lIGJhc2ljIG91dHB1dCBkZXNjcmlwdGlvbnMgcHJpbnRlZCB0byBzY3JlZW4Kb3V0X2Rlc2NyaWJlKGZsYXJlX2ZpdCxuc3ViKQoKIyBleHRyYWN0IGZpdCBkYXRhCnN1bW1hcnlfZmxhcmUgPC0gc3VtbWFyeShmbGFyZV9maXQpCgpgYGAKCgojIyMjIENyZWF0ZSBCSUMgZnJvbSBsb2cgbGlrZWxpaG9vZAoKYGBge3J9CiMjIGV4dHJhY3QgbG9nIGxpa2VsaWhvb2QKCmZsYXJlX2xvZ2xpa2UgPC0gZXh0cmFjdF9sb2dfbGlrKGZsYXJlX2ZpdCwgcGFyYW1ldGVyX25hbWUgPSAibG9nbGlrIiwgbWVyZ2VfY2hhaW5zID0gVFJVRSkKCiNjYWxjdWxhdGUgQklDCgpGTEFSZV9iaWM8LWJpYyhudHJpYWxzLC1jb2xNZWFucyhmbGFyZV9sb2dsaWtlKSwyKSAjbnVtYmVyIG9mIHBhcmFtZXRlcnMgaW4gdGhhdCBtb2RlbCBlLmcuIDQpCgojIyBtZWFuIEJJQyBhcyBtb2RlbCBjb21wYXJpc29ucyB0b29sOgoKcHJpbnQoIk1lYW4gQmF5ZXNpYW4gaW5mb3JtYXRpb24gY3JpdGVyaW9uIGZvciBtb2RlbCIpCgptZWFuKEZMQVJlX2JpYykKCmBgYAoKIyMjIyBBZGQgdG8gYmFyIHBsb3QKCmBgYHtyfQoKbW9kX2NvbXAgPC0gcmJpbmQobmEub21pdChtb2RfY29tcCksYygiUHVuaXNobWVudCBzZW5zaXRpdml0eSIsbWVhbihGTEFSZV9iaWMpKSkKCm1vZF9jb21wJEJJQyA8LSBvZHAoYXMubnVtZXJpYyhtb2RfY29tcCRCSUMpKQoKbW9kX2NvbXAgPC0gYXMuZGF0YS5mcmFtZShuYS5vbWl0KG1vZF9jb21wKSkKCgojIyBwbG90IGZ1bmN0aW9uIC0gY3JlYXRlIHBsb3QKcGxvdF9tb2RlbHMobW9kX2NvbXApCgpgYGAKCgojIyMgR2VuZXJhdGUKIyMjIyMgTWFrZSBhbHBoYSAvIGJldGEgZGF0YXNldHMgcC9wCgpVc2UgdGhlIHN1bW1hcnkgb2YgdGhlIHN0YW4gbW9kZWwgdG8gZXh0cmFjdCB0aGUgZGlmZmVyZW50IHBhcmFtZXRlcnMgd2Ugd2FudCB0byB0cnkgdG8gdXNlIHRvIHJlY3JlYXRlIG91ciBkYXRhLgoKYGBge3J9CgpwYXJhbXMgPC0gc3VtbWFyeShmbGFyZV9maXQpCmFscGhhX2VzdCA8LSBkYXRhLmZyYW1lKHBhcmFtcyRzdW1tYXJ5WzE6bnN1YiwxXSkKYmV0YSA8LSBkYXRhLmZyYW1lKHBhcmFtcyRzdW1tYXJ5Wyhuc3ViKzEpOihuc3ViKjIpLDFdKQpsYW1iZGEgPC0gZGF0YS5mcmFtZShwYXJhbXMkc3VtbWFyeVsobnN1YiozKzEpOihuc3ViKjQpLDFdKQoKbmFtZXMoYWxwaGFfZXN0KSA8LSAiYWxwaGEiCm5hbWVzKGJldGEpIDwtICJiZXRhIgpuYW1lcyhsYW1iZGEpIDwtICJsYW1iZGEiCiAgCgpgYGAKCiMjIyMjIEluaXRpYWxpc2UgZW1wdHkgZGF0YXNldHMgdG8gaG9sZCB0aGUgcHJlZGljdGVkIHJhdGluZ3MKCmBgYHtyfQoKcmF0aW5nX2VzdF9wbHVzIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9bnRyaWFscyxucm93PW5zdWIpKQpyYXRpbmdfZXN0X21pbnVzIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9bnRyaWFscyxucm93PW5zdWIpKQoKIyBiZXRhIHNoYXBlIHBhcmFtZXRlcnMKc2hhcGUxcCA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPW50cmlhbHMsbnJvdz1uc3ViKSkKc2hhcGUxbSA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPW50cmlhbHMsbnJvdz1uc3ViKSkKc2hhcGUycCA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPW50cmlhbHMsbnJvdz1uc3ViKSkKc2hhcGUybSA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPW50cmlhbHMsbnJvdz1uc3ViKSkKCiMgViBwYXJhbWV0ZXJzIChpbml0aWFsaXNlZCBhdCByYW5kb20gdmFsdWUgYmV0d2VlbiAwLjUgLSAwLjA1IGFuZCAwLjUrMC4wNSkKCnZwIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9bnRyaWFscyxucm93PW5zdWIpKQp2bSA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPW50cmlhbHMsbnJvdz1uc3ViKSkKCnZwWzFdIDwtIHJub3JtKG5zdWIsMC41LDAuMDI1KQp2bVsxXSA8LSBybm9ybShuc3ViLDAuNSwwLjAyNSkKCgojIHByZWRpY3Rpb24gZXJyb3IgCgpkcCA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPShudHJpYWxzLTEpLG5yb3c9bnN1YikpIApkbSA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sPShudHJpYWxzLTEpLG5yb3c9bnN1YikpIAoKICAKYGBgCgojIyMjIyBTaW11bGF0ZSByYXRpbmdzCgpVc2Ugb3VyIGV4dHJhY3RlZCBwYXJhbWV0ZXJzIGluIHBsYWNlIG9mIGVzdGltYXRpbmcgdGhlIHNhbWUuIFVzZSB0aGUgc3RhbiBzeW50YXgKCgojIyMjIyMgIFBvcHVsYXRlIG91ciB2cGx1cyBhbmQgZGVsdGEgZnJhbWVzCgp1c2UgdGhlIGFscGhhIHBhcmFtZXRlcnMgd2UndmUgZXh0cmFjdGVkIChhbHBoYV9lc3QpCmQgPT0gZGVsdGEgKHByZWNkaWN0aW9uIGVycm9yKQp2ID09IHZhbHVlIChpLmUuIHZhbHVlIGZvciBlYWNoIHN0aW11bHVzKQoKCmBgYHtyfQoKZm9yIChwIGluIDE6bnN1Yil7CiAgZm9yICh0IGluIDE6KG50cmlhbHMtMSkpewogICAgICBkcFtwLHRdIDwtIHNjcmVhbVBsdXNbcCx0XSpsYW1iZGFbcCxdLXZwW3AsdF0KICAgICAgZG1bcCx0XSA8LSBzY3JlYW1NaW51c1twLHRdKmxhbWJkYVtwLF0tdm1bcCx0XQogICAgICB2cFtwLHQrMV0gPC0gdnBbcCx0XSthbHBoYV9lc3RbcCwxXSpkcFtwLHRdCiAgICAgIHZtW3AsdCsxXTwtIHZtW3AsdF0rYWxwaGFfZXN0W3AsMV0qZG1bcCx0XQogICAgfQp9CgpgYGAKCiAgICBmb3IgKHQgaW4gMTpudHJpYWxzKXsKICAgICAgc2hhcGUxX1BsdXNbdCxwXSA9IFZQbHVzW3QscF0gKiAoKFZQbHVzW3QscF0gKiAoMS1WUGx1c1t0LHBdKSkgLyBiZXRhW3AsMV0pOwogICAgICBzaGFwZTFfTWludXNbdCxwXSA9IFZNaW51c1t0LHBdICogKChWTWludXNbdCxwXSAqICgxLVZNaW51c1t0LHBdKSkgLyBiZXRhW3AsMl0pOwogICAgICBzaGFwZTJfUGx1c1t0LHBdID0gKDEtVlBsdXNbdCxwXSkgKiAoKFZQbHVzW3QscF0gKiAoMS1WUGx1c1t0LHBdKSkgLyBiZXRhW3AsMV0pOwogICAgICBzaGFwZTJfTWludXNbdCxwXSA9ICgxLVZNaW51c1t0LHBdKSAqICgoVk1pbnVzW3QscF0gKiAoMS1WTWludXNbdCxwXSkpIC8gYmV0YVtwLDJdKTsKCiAgICAgIHJhdGluZ3NQbHVzW3QscF0gfiBiZXRhKHNoYXBlMV9QbHVzW3QscF0sc2hhcGUyX1BsdXNbdCxwXSk7CiAgICAgIHJhdGluZ3NNaW51c1t0LHBdIH4gYmV0YShzaGFwZTFfTWludXNbdCxwXSxzaGFwZTJfTWludXNbdCxwXSk7CiAgICB9CiAgfQp9CgoKIyMjIyMjIHBvcHVsYXRlIGJldGEgcGFyYW1ldGVyIHNoYXBlIGZyYW1lcwoKVXNlIHRoZSBuZXcgdiBmcmFtZXMgYW5kIGJldGEgcGFyYW1ldGVycy4KClNoYXBlIDEgYW5kIDIgYXJlIHN1ZmZpY2llbnQgcGFyYW1ldGVycyBmb3IgdGhlIGJldGEgZGlzdHJpYnV0aW9uCgpgYGB7cn0KCmZvciAocCBpbiAxOm5zdWIpewogIAogIGZvciAodCBpbiAxOm50cmlhbHMpewogICAgCiAgICAgIHNoYXBlMXBbcCx0XSA9IHZwW3AsdF0gKiAoKHZwW3AsdF0gKiAoMS12cFtwLHRdKSkgLyBiZXRhW3AsMV0pCiAgICAgIHNoYXBlMW1bcCx0XSA9IHZtW3AsdF0gKiAoKHZtW3AsdF0gKiAoMS12bVtwLHRdKSkgLyBiZXRhW3AsMV0pCiAgICAgIHNoYXBlMnBbcCx0XSA9ICgxLXZwW3AsdF0pICogKCh2cFtwLHRdICogKDEtdnBbcCx0XSkpIC8gYmV0YVtwLDFdKQogICAgICBzaGFwZTJtW3AsdF0gPSAoMS12bVtwLHRdKSAqICgodm1bcCx0XSAqICgxLXZtW3AsdF0pKSAvIGJldGFbcCwxXSkKICAgICAgCiAgfQp9CiAgCgpgYGAKCgojIyMjIyMgRXN0aW1hdGUgcmF0aW5ncwoKCnRyeWluZyB0byB1c2UgcGJldGEgaGVyZSAoZGVyaXZlcyB0aGUgZGlzdHJpYnV0aW9uIGZ1bmN0aW9uIGdpdmVtbiBhIHNldCBvZiBwcm9iYWJpbGl0aWVzKSAKCkZvciBub3csIHNldHRpbmcgcHJvYmFiaWxpdGllcyBiZXR3ZWVuIDAgYW5kIDEgYW5kIHRha2luZyB0aGUgYXZlcmFnZS4uLgpgYGB7cn0KCgpmb3IgKHAgaW4gMTpuc3ViKXsKICAKICBmb3IgKHQgaW4gMTpudHJpYWxzKXsKICAgIAogICAgcmF0aW5nX2VzdF9wbHVzW3AsdF0gPC0gbWVhbihyYmV0YSgxMDAwLHNoYXBlMXBbcCx0XSxzaGFwZTJwW3AsdF0pKQogICAgcmF0aW5nX2VzdF9taW51c1twLHRdIDwtIG1lYW4ocmJldGEoMTAwMCxzaGFwZTFtW3AsdF0sc2hhcGUybVtwLHRdKSkKICAgIAogIH0KfQoKCmBgYAoKIyMjIyBDb3JyZWxhdGUgYWN0dWFsIHJhdGluZ3Mgd2l0aCBzaW11bGF0ZWQgcmF0aW5ncwoKdXNlIHRoZSBzaW11bGF0ZWQgcmF0aW5ncyBwZXIgcGVyc29uIHRoYXQgd2UgaGF2ZSBkZXJpdmVkIHVzaW5nIG91ciBwYXJhbWV0ZXJzIGFuZCBzZWUgaG93IHdlbGwgdGhleSBhbGlnbiB3aXRoIHRoZSByZWFsIHJhdGluZ3MuLi4KCk9ubHkgc2hvd2luZyB0aGUgZGlhZ2Fub2xzIGZyb20gY29yci50ZXN0IHBhY2thZ2UgaGVyZSB0byBnZXQgdGhlIGltcG9ydGFudCB0MSB4IHQxIGV0YyB2YWx1ZXMuCgpgYGB7cn0KCnByaW50KCJyZWFsIHJhdGluZ3Mgd2l0aCBlc3RpbWF0ZWQgcmF0aW5nczogQ1MgTUlOVVMiKQpkaWFnKGNvcnIudGVzdChyYXRpbmdfZXN0X21pbnVzLG1pbnVzX3NjYWxlZCkkcikKCnByaW50KCJyZWFsIHJhdGluZ3Mgd2l0aCBlc3RpbWF0ZWQgcmF0aW5nczogQ1MgTUlOVVMgKGF2ZXJhZ2UgZm9yIGFsbCB0cmlhbHMpIikKY29yKHJvd01lYW5zKHJhdGluZ19lc3RfbWludXMpLHJvd01lYW5zKG1pbnVzX3NjYWxlZCkpCgoKcHJpbnQoInJlYWwgcmF0aW5ncyB3aXRoIGVzdGltYXRlZCByYXRpbmdzOiBDUyBQTFVTIikKZGlhZyhjb3JyLnRlc3QocmF0aW5nX2VzdF9wbHVzLHBsdXNfc2NhbGVkKSRyKQoKcHJpbnQoInJlYWwgcmF0aW5ncyB3aXRoIGVzdGltYXRlZCByYXRpbmdzOiBDUyBQTFVTIChhdmVyYWdlIGZvciBhbGwgdHJpYWxzKSIpCmNvcihyb3dNZWFucyhyYXRpbmdfZXN0X3BsdXMpLHJvd01lYW5zKHBsdXNfc2NhbGVkKSkKCgpgYGAKCiMjIyBSZWNvdmVyCgpIZXJlIHdlIGFyZSBzZWVpbmcgaWYgd2UgY2FuIHJlY292ZXIgdGhlIHNhbWUgZXN0aW1hdGVzIHVzaW5nIHRoZSBzaW11bGF0ZWQgcmF0aW5ncy4gQmFzaWNhbGx5IHJ1biBzdGFuIGJ1dCB1c2luZyB0aGUgZXN0aW1hdGVkIHJhdGluZ3MgaW5zdGVhZCBvZiB0aGUgcmVhbCBvbmVzLiBTZWUgaWYgd2UgZ2V0IHRoZSBzYW1lIGFscGhhIC8gYmV0YSBwYXJhbWV0ZXJzLgoKIyMjIyBydW4gc3RhbiBtb2RlbAoKYGBge3IgcHVuaXNobWVudCBzZW5zaXRpdml0eSByZWNvdmVyIHNldCB1cH0KI3NjcmlwdApzdGFubmFtZT0nYmV0YV9tZWFuMWJldGFfUHVuU2Vucy5zdGFuJwoKIyBkYXRhIApmbGFyZV9kYXRhX3JlYzwtbGlzdChudHJpYWxzPW50cmlhbHMsbnN1Yj1uc3ViLHNjcmVhbVBsdXMgPSB0KHNjcmVhbVBsdXMpLCBzY3JlYW1NaW51cz0gdChzY3JlYW1NaW51cykscmF0aW5nc1BsdXM9dChyYXRpbmdfZXN0X3BsdXMpLHJhdGluZ3NNaW51cz10KHJhdGluZ19lc3RfbWludXMpLGNkZl9zY2FsZT1jZGZfc2NhbGUpCmBgYAoKCmBgYHtyIHB1bmlzaG1lbnQgc2Vuc2l0aXZpdHkgcmVjb3Zlcn0KCmZsYXJlX2ZpdF9yZWMgPC0gbW9kZWxfcnVuKCdmdWxsJyxzdGFubmFtZSxmbGFyZV9kYXRhX3JlYykKCiMjIGdldCBzb21lIGJhc2ljIG91dHB1dCBkZXNjcmlwdGlvbnMgcHJpbnRlZCB0byBzY3JlZW4Kb3V0X2Rlc2NyaWJlKGZsYXJlX2ZpdF9yZWMsbnN1YikKCmBgYAoKCiMjIyMgTWFrZSBhbHBoYSAvIGJldGEgZGF0YXNldHMgcC9wCgpVc2UgdGhlIHN1bW1hcnkgb2YgdGhlIHN0YW4gbW9kZWwgdG8gZXh0cmFjdCB0aGUgZGlmZmVyZW50IHBhcmFtZXRlcnMgd2Ugd2FudCB0byB0cnkgdG8gdXNlIHRvIHJlY3JlYXRlIG91ciBkYXRhLgoKYGBge3J9CgpwYXJhbXNfcmVjIDwtIHN1bW1hcnkoZmxhcmVfZml0X3JlYykKYWxwaGFfZXN0X3JlYyA8LSBkYXRhLmZyYW1lKHBhcmFtc19yZWMkc3VtbWFyeVsxOm5zdWIsMV0pCmJldGFfcmVjIDwtIGRhdGEuZnJhbWUocGFyYW1zX3JlYyRzdW1tYXJ5Wyhuc3ViKzEpOihuc3ViKjIpLDFdKQpsYW1iZGFfcmVjIDwtIGRhdGEuZnJhbWUocGFyYW1zX3JlYyRzdW1tYXJ5Wyhuc3ViKjMrMSk6KG5zdWIqNCksMV0pCgoKYGBgCgojIyMjIENvcnJlbGF0ZSBhY3R1YWwgcmF0aW5ncyB3aXRoIHNpbXVsYXRlZCByYXRpbmdzCgp1c2UgdGhlIHNpbXVsYXRlZCByYXRpbmdzIHBlciBwZXJzb24gdGhhdCB3ZSBoYXZlIGRlcml2ZWQgdXNpbmcgb3VyIHBhcmFtZXRlcnMgYW5kIHNlZSBob3cgd2VsbCB0aGV5IGFsaWduIHdpdGggdGhlIHJlYWwgcmF0aW5ncy4uLgoKT25seSBzaG93aW5nIHRoZSBkaWFnYW5vbHMgZnJvbSBjb3JyLnRlc3QgcGFja2FnZSBoZXJlIHRvIGdldCB0aGUgaW1wb3J0YW50IHQxIHggdDEgZXRjIHZhbHVlcy4KCmBgYHtyfQoKcHJpbnQoIm9yaWdpbmFsIHdpdGggcmVjb3ZlcmVkOiBBTFBIQSIpCmRpYWcoY29yci50ZXN0KGFscGhhX2VzdF9yZWMsYWxwaGFfZXN0KSRyKQoKcHJpbnQoIm9yaWdpbmFsIHdpdGggcmVjb3ZlcmVkOiBCRVRBIikKZGlhZyhjb3JyLnRlc3QoYmV0YV9yZWMsYmV0YSkkcikKCnByaW50KCJvcmlnaW5hbCB3aXRoIHJlY292ZXJlZDogTEFNQkRBIikKZGlhZyhjb3JyLnRlc3QobGFtYmRhX3JlYyxsYW1iZGEpJHIpCgpgYGAKCkJldGEgaXMgdmVyeSBwb29ybHkgcmVjb3ZlcmVkIGhlcmUuIEFscGhhIGFuZCBMYW1iZGEgYXJlIHJlY292ZXJlZCBleGNlcHRpb25hbGx5IHdlbGwuIAoKV2lsbCB0cnkgYSBxdWljayAyIGJldGEgbWRvZWwgd2l0aCBwdW5pc2htZW50IHNlbnNpdGl2aXR5IHRvIHNlZSBpZiB0aGlzIGltcHJvdmVzIHRoaW5ncy4gCgoKCiMjIE1vZGVsIDk6IFB1bmlzaG1lbnQgc2Vuc2l0aXZpdHkgMiBiZXRhCgoKIyMjIE1vZGVsCgpgYGB7ciBwdW5pc2htZW50IHNlbnNpdGl2aXR5IDIgYmV0YSBzZXQgdXB9CiNzY3JpcHQKc3Rhbm5hbWU9J2JldGFfbWVhbjFiZXRhX1B1blNlbnMyQmV0YS5zdGFuJwoKYGBgCgoKYGBge3IgcHVuaXNobWVudCBzZW5zaXRpdml0eSAyIGJldGF9CgpmbGFyZV9maXQgPC0gbW9kZWxfcnVuKCdmdWxsJyxzdGFubmFtZSxmbGFyZV9kYXRhKQoKIyMgZ2V0IHNvbWUgYmFzaWMgb3V0cHV0IGRlc2NyaXB0aW9ucyBwcmludGVkIHRvIHNjcmVlbgpvdXRfZGVzY3JpYmUoZmxhcmVfZml0LG5zdWIpCgojIGV4dHJhY3QgZml0IGRhdGEKc3VtbWFyeV9mbGFyZSA8LSBzdW1tYXJ5KGZsYXJlX2ZpdCkKCmBgYAoKCiMjIyMgQ3JlYXRlIEJJQyBmcm9tIGxvZyBsaWtlbGlob29kCgpgYGB7cn0KIyMgZXh0cmFjdCBsb2cgbGlrZWxpaG9vZAoKZmxhcmVfbG9nbGlrZSA8LSBleHRyYWN0X2xvZ19saWsoZmxhcmVfZml0LCBwYXJhbWV0ZXJfbmFtZSA9ICJsb2dsaWsiLCBtZXJnZV9jaGFpbnMgPSBUUlVFKQoKI2NhbGN1bGF0ZSBCSUMKCkZMQVJlX2JpYzwtYmljKG50cmlhbHMsLWNvbE1lYW5zKGZsYXJlX2xvZ2xpa2UpLDIpICNudW1iZXIgb2YgcGFyYW1ldGVycyBpbiB0aGF0IG1vZGVsIGUuZy4gNCkKCiMjIG1lYW4gQklDIGFzIG1vZGVsIGNvbXBhcmlzb25zIHRvb2w6CgpwcmludCgiTWVhbiBCYXllc2lhbiBpbmZvcm1hdGlvbiBjcml0ZXJpb24gZm9yIG1vZGVsIikKCm1lYW4oRkxBUmVfYmljKQoKYGBgCgojIyMjIEFkZCB0byBiYXIgcGxvdAoKYGBge3J9Cgptb2RfY29tcCA8LSByYmluZChuYS5vbWl0KG1vZF9jb21wKSxjKCJQdW5pc2htZW50IHNlbnNpdGl2aXR5IDIgYmV0YSIsbWVhbihGTEFSZV9iaWMpKSkKCm1vZF9jb21wJEJJQyA8LSBvZHAoYXMubnVtZXJpYyhtb2RfY29tcCRCSUMpKQoKbW9kX2NvbXAgPC0gYXMuZGF0YS5mcmFtZShuYS5vbWl0KG1vZF9jb21wKSkKCgojIyBwbG90IGZ1bmN0aW9uIC0gY3JlYXRlIHBsb3QKcGxvdF9tb2RlbHMobW9kX2NvbXApCgpgYGAKCiMjIyBHZW5lcmF0ZQojIyMjIyBNYWtlIGFscGhhIC8gYmV0YSBkYXRhc2V0cyBwL3AKClVzZSB0aGUgc3VtbWFyeSBvZiB0aGUgc3RhbiBtb2RlbCB0byBleHRyYWN0IHRoZSBkaWZmZXJlbnQgcGFyYW1ldGVycyB3ZSB3YW50IHRvIHRyeSB0byB1c2UgdG8gcmVjcmVhdGUgb3VyIGRhdGEuCgpgYGB7cn0KCnBhcmFtcyA8LSBzdW1tYXJ5KGZsYXJlX2ZpdCkKYWxwaGFfZXN0IDwtIGRhdGEuZnJhbWUocGFyYW1zJHN1bW1hcnlbMTpuc3ViLDFdKQpiZXRhX2FsbCA8LSBkYXRhLmZyYW1lKHBhcmFtcyRzdW1tYXJ5Wyhuc3ViKzEpOihuc3ViKjMpLDFdKQpsYW1iZGEgPC0gZGF0YS5mcmFtZShwYXJhbXMkc3VtbWFyeVsobnN1Yio0KzEpOihuc3ViKjUpLDFdKQoKIyBkaXZpZGUgYmV0YSBpbnRvIHRoZSB0d28uLi4KCiMjIHAgaXMgMSwgc28gdGhlIG9kZCByb3dzCmJldGFfcCA8LSBkYXRhLmZyYW1lKGJldGFfYWxsWyBjKFRSVUUsRkFMU0UpLCBdKSAjIG9kZCByb3dzCmJldGFfbSA8LSBkYXRhLmZyYW1lKGJldGFfYWxsWyAhYyhUUlVFLEZBTFNFKSwgXSkgIyBldmVuIHJvd3MKCm5hbWVzKGFscGhhX2VzdCkgPC0gImFscGhhIgpuYW1lcyhiZXRhX3ApIDwtICJiZXRhX3BsdXMiCm5hbWVzKGJldGFfbSkgPC0gImJldGFfbWludXMiCm5hbWVzKGxhbWJkYSkgPC0gImxhbWJkYSIKICAKCmBgYAoKIyMjIyMgSW5pdGlhbGlzZSBlbXB0eSBkYXRhc2V0cyB0byBob2xkIHRoZSBwcmVkaWN0ZWQgcmF0aW5ncwoKYGBge3J9CgpyYXRpbmdfZXN0X3BsdXMgPC0gZGF0YS5mcmFtZShtYXRyaXgobmNvbD1udHJpYWxzLG5yb3c9bnN1YikpCnJhdGluZ19lc3RfbWludXMgPC0gZGF0YS5mcmFtZShtYXRyaXgobmNvbD1udHJpYWxzLG5yb3c9bnN1YikpCgojIGJldGEgc2hhcGUgcGFyYW1ldGVycwpzaGFwZTFwIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9bnRyaWFscyxucm93PW5zdWIpKQpzaGFwZTFtIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9bnRyaWFscyxucm93PW5zdWIpKQpzaGFwZTJwIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9bnRyaWFscyxucm93PW5zdWIpKQpzaGFwZTJtIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9bnRyaWFscyxucm93PW5zdWIpKQoKIyBWIHBhcmFtZXRlcnMgKGluaXRpYWxpc2VkIGF0IHJhbmRvbSB2YWx1ZSBiZXR3ZWVuIDAuNSAtIDAuMDUgYW5kIDAuNSswLjA1KQoKdnAgPC0gZGF0YS5mcmFtZShtYXRyaXgobmNvbD1udHJpYWxzLG5yb3c9bnN1YikpCnZtIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9bnRyaWFscyxucm93PW5zdWIpKQoKdnBbMV0gPC0gcm5vcm0obnN1YiwwLjUsMC4wMjUpCnZtWzFdIDwtIHJub3JtKG5zdWIsMC41LDAuMDI1KQoKCiMgcHJlZGljdGlvbiBlcnJvciAKCmRwIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9KG50cmlhbHMtMSksbnJvdz1uc3ViKSkgCmRtIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2w9KG50cmlhbHMtMSksbnJvdz1uc3ViKSkgCgogIApgYGAKCiMjIyMjIFNpbXVsYXRlIHJhdGluZ3MKClVzZSBvdXIgZXh0cmFjdGVkIHBhcmFtZXRlcnMgaW4gcGxhY2Ugb2YgZXN0aW1hdGluZyB0aGUgc2FtZS4gVXNlIHRoZSBzdGFuIHN5bnRheAoKCiMjIyMjIyAgUG9wdWxhdGUgb3VyIHZwbHVzIGFuZCBkZWx0YSBmcmFtZXMKCnVzZSB0aGUgYWxwaGEgcGFyYW1ldGVycyB3ZSd2ZSBleHRyYWN0ZWQgKGFscGhhX2VzdCkKZCA9PSBkZWx0YSAocHJlY2RpY3Rpb24gZXJyb3IpCnYgPT0gdmFsdWUgKGkuZS4gdmFsdWUgZm9yIGVhY2ggc3RpbXVsdXMpCgoKYGBge3J9Cgpmb3IgKHAgaW4gMTpuc3ViKXsKICBmb3IgKHQgaW4gMToobnRyaWFscy0xKSl7CiAgICAgIGRwW3AsdF0gPC0gc2NyZWFtUGx1c1twLHRdKmxhbWJkYVtwLF0tdnBbcCx0XQogICAgICBkbVtwLHRdIDwtIHNjcmVhbU1pbnVzW3AsdF0qbGFtYmRhW3AsXS12bVtwLHRdCiAgICAgIHZwW3AsdCsxXSA8LSB2cFtwLHRdK2FscGhhX2VzdFtwLDFdKmRwW3AsdF0KICAgICAgdm1bcCx0KzFdPC0gdm1bcCx0XSthbHBoYV9lc3RbcCwxXSpkbVtwLHRdCiAgICB9Cn0KCmBgYAoKICAgIGZvciAodCBpbiAxOm50cmlhbHMpewogICAgICBzaGFwZTFfUGx1c1t0LHBdID0gVlBsdXNbdCxwXSAqICgoVlBsdXNbdCxwXSAqICgxLVZQbHVzW3QscF0pKSAvIGJldGFbcCwxXSk7CiAgICAgIHNoYXBlMV9NaW51c1t0LHBdID0gVk1pbnVzW3QscF0gKiAoKFZNaW51c1t0LHBdICogKDEtVk1pbnVzW3QscF0pKSAvIGJldGFbcCwyXSk7CiAgICAgIHNoYXBlMl9QbHVzW3QscF0gPSAoMS1WUGx1c1t0LHBdKSAqICgoVlBsdXNbdCxwXSAqICgxLVZQbHVzW3QscF0pKSAvIGJldGFbcCwxXSk7CiAgICAgIHNoYXBlMl9NaW51c1t0LHBdID0gKDEtVk1pbnVzW3QscF0pICogKChWTWludXNbdCxwXSAqICgxLVZNaW51c1t0LHBdKSkgLyBiZXRhW3AsMl0pOwoKICAgICAgcmF0aW5nc1BsdXNbdCxwXSB+IGJldGEoc2hhcGUxX1BsdXNbdCxwXSxzaGFwZTJfUGx1c1t0LHBdKTsKICAgICAgcmF0aW5nc01pbnVzW3QscF0gfiBiZXRhKHNoYXBlMV9NaW51c1t0LHBdLHNoYXBlMl9NaW51c1t0LHBdKTsKICAgIH0KICB9Cn0KCgojIyMjIyMgcG9wdWxhdGUgYmV0YSBwYXJhbWV0ZXIgc2hhcGUgZnJhbWVzCgpVc2UgdGhlIG5ldyB2IGZyYW1lcyBhbmQgYmV0YSBwYXJhbWV0ZXJzLgoKU2hhcGUgMSBhbmQgMiBhcmUgc3VmZmljaWVudCBwYXJhbWV0ZXJzIGZvciB0aGUgYmV0YSBkaXN0cmlidXRpb24KCmBgYHtyfQoKZm9yIChwIGluIDE6bnN1Yil7CiAgCiAgZm9yICh0IGluIDE6bnRyaWFscyl7CiAgICAKICAgICAgc2hhcGUxcFtwLHRdID0gdnBbcCx0XSAqICgodnBbcCx0XSAqICgxLXZwW3AsdF0pKSAvIGJldGFfcFtwLDFdKQogICAgICBzaGFwZTJwW3AsdF0gPSAoMS12cFtwLHRdKSAqICgodnBbcCx0XSAqICgxLXZwW3AsdF0pKSAvIGJldGFfcFtwLDFdKQogICAgICBzaGFwZTFtW3AsdF0gPSB2bVtwLHRdICogKCh2bVtwLHRdICogKDEtdm1bcCx0XSkpIC8gYmV0YV9tW3AsMV0pCiAgICAgIHNoYXBlMm1bcCx0XSA9ICgxLXZtW3AsdF0pICogKCh2bVtwLHRdICogKDEtdm1bcCx0XSkpIC8gYmV0YV9tW3AsMV0pCiAgICAgIAogIH0KfQogIAoKYGBgCgoKIyMjIyMjIEVzdGltYXRlIHJhdGluZ3MKCgp0cnlpbmcgdG8gdXNlIHBiZXRhIGhlcmUgKGRlcml2ZXMgdGhlIGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiBnaXZlbW4gYSBzZXQgb2YgcHJvYmFiaWxpdGllcykgCgpGb3Igbm93LCBzZXR0aW5nIHByb2JhYmlsaXRpZXMgYmV0d2VlbiAwIGFuZCAxIGFuZCB0YWtpbmcgdGhlIGF2ZXJhZ2UuLi4KYGBge3J9CgoKZm9yIChwIGluIDE6bnN1Yil7CiAgCiAgZm9yICh0IGluIDE6bnRyaWFscyl7CiAgICAKICAgIHJhdGluZ19lc3RfcGx1c1twLHRdIDwtIG1lYW4ocmJldGEoMTAwMCxzaGFwZTFwW3AsdF0sc2hhcGUycFtwLHRdKSkKICAgIHJhdGluZ19lc3RfbWludXNbcCx0XSA8LSBtZWFuKHJiZXRhKDEwMDAsc2hhcGUxbVtwLHRdLHNoYXBlMm1bcCx0XSkpCiAgICAKICB9Cn0KCgpgYGAKCiMjIyMgQ29ycmVsYXRlIGFjdHVhbCByYXRpbmdzIHdpdGggc2ltdWxhdGVkIHJhdGluZ3MKCnVzZSB0aGUgc2ltdWxhdGVkIHJhdGluZ3MgcGVyIHBlcnNvbiB0aGF0IHdlIGhhdmUgZGVyaXZlZCB1c2luZyBvdXIgcGFyYW1ldGVycyBhbmQgc2VlIGhvdyB3ZWxsIHRoZXkgYWxpZ24gd2l0aCB0aGUgcmVhbCByYXRpbmdzLi4uCgpPbmx5IHNob3dpbmcgdGhlIGRpYWdhbm9scyBmcm9tIGNvcnIudGVzdCBwYWNrYWdlIGhlcmUgdG8gZ2V0IHRoZSBpbXBvcnRhbnQgdDEgeCB0MSBldGMgdmFsdWVzLgoKYGBge3J9CgpwcmludCgicmVhbCByYXRpbmdzIHdpdGggZXN0aW1hdGVkIHJhdGluZ3M6IENTIE1JTlVTIikKZGlhZyhjb3JyLnRlc3QocmF0aW5nX2VzdF9taW51cyxtaW51c19zY2FsZWQpJHIpCgpwcmludCgicmVhbCByYXRpbmdzIHdpdGggZXN0aW1hdGVkIHJhdGluZ3M6IENTIE1JTlVTIChhdmVyYWdlIGZvciBhbGwgdHJpYWxzKSIpCmNvcihyb3dNZWFucyhyYXRpbmdfZXN0X21pbnVzKSxyb3dNZWFucyhtaW51c19zY2FsZWQpKQoKCnByaW50KCJyZWFsIHJhdGluZ3Mgd2l0aCBlc3RpbWF0ZWQgcmF0aW5nczogQ1MgUExVUyIpCmRpYWcoY29yci50ZXN0KHJhdGluZ19lc3RfcGx1cyxwbHVzX3NjYWxlZCkkcikKCnByaW50KCJyZWFsIHJhdGluZ3Mgd2l0aCBlc3RpbWF0ZWQgcmF0aW5nczogQ1MgUExVUyAoYXZlcmFnZSBmb3IgYWxsIHRyaWFscykiKQpjb3Iocm93TWVhbnMocmF0aW5nX2VzdF9wbHVzKSxyb3dNZWFucyhwbHVzX3NjYWxlZCkpCgoKYGBgCgoKVGhlIGdlbmVyYXRpbmcgcmF0aW5ncyBhcmUgd29yc2Ugd2l0aCB0aGlzIG1vZGVsIG92ZXJhbGwuCgojIyMgUmVjb3ZlcgoKSGVyZSB3ZSBhcmUgc2VlaW5nIGlmIHdlIGNhbiByZWNvdmVyIHRoZSBzYW1lIGVzdGltYXRlcyB1c2luZyB0aGUgc2ltdWxhdGVkIHJhdGluZ3MuIEJhc2ljYWxseSBydW4gc3RhbiBidXQgdXNpbmcgdGhlIGVzdGltYXRlZCByYXRpbmdzIGluc3RlYWQgb2YgdGhlIHJlYWwgb25lcy4gU2VlIGlmIHdlIGdldCB0aGUgc2FtZSBhbHBoYSAvIGJldGEgcGFyYW1ldGVycy4KCiMjIyMgcnVuIHN0YW4gbW9kZWwKCmBgYHtyIHB1bmlzaG1lbnQgc2Vuc2l0aXZpdHkgMmJldGEgcmVjb3ZlciBzZXQgdXB9CiNzY3JpcHQKc3Rhbm5hbWU9J2JldGFfbWVhbjFiZXRhX1B1blNlbnMyQmV0YS5zdGFuJwoKIyBkYXRhIApmbGFyZV9kYXRhX3JlYzwtbGlzdChudHJpYWxzPW50cmlhbHMsbnN1Yj1uc3ViLHNjcmVhbVBsdXMgPSB0KHNjcmVhbVBsdXMpLCBzY3JlYW1NaW51cz0gdChzY3JlYW1NaW51cykscmF0aW5nc1BsdXM9dChyYXRpbmdfZXN0X3BsdXMpLHJhdGluZ3NNaW51cz10KHJhdGluZ19lc3RfbWludXMpLGNkZl9zY2FsZT1jZGZfc2NhbGUpCmBgYAoKCmBgYHtyIHB1bmlzaG1lbnQgc2Vuc2l0aXZpdHkgMiBiZXRhIHJlY292ZXJ9CgpmbGFyZV9maXRfcmVjIDwtIG1vZGVsX3J1bignZnVsbCcsc3Rhbm5hbWUsZmxhcmVfZGF0YV9yZWMpCgojIyBnZXQgc29tZSBiYXNpYyBvdXRwdXQgZGVzY3JpcHRpb25zIHByaW50ZWQgdG8gc2NyZWVuCm91dF9kZXNjcmliZShmbGFyZV9maXRfcmVjLG5zdWIpCgpgYGAKCgojIyMjIE1ha2UgYWxwaGEgLyBiZXRhIGRhdGFzZXRzIHAvcAoKVXNlIHRoZSBzdW1tYXJ5IG9mIHRoZSBzdGFuIG1vZGVsIHRvIGV4dHJhY3QgdGhlIGRpZmZlcmVudCBwYXJhbWV0ZXJzIHdlIHdhbnQgdG8gdHJ5IHRvIHVzZSB0byByZWNyZWF0ZSBvdXIgZGF0YS4KCmBgYHtyfQoKCnBhcmFtc19yZWMgPC0gc3VtbWFyeShmbGFyZV9maXRfcmVjKQphbHBoYV9lc3RfcmVjIDwtIGRhdGEuZnJhbWUocGFyYW1zX3JlYyRzdW1tYXJ5WzE6bnN1YiwxXSkKYmV0YV9hbGxfcmVjIDwtIGRhdGEuZnJhbWUocGFyYW1zX3JlYyRzdW1tYXJ5Wyhuc3ViKzEpOihuc3ViKjMpLDFdKQpsYW1iZGFfcmVjIDwtIGRhdGEuZnJhbWUocGFyYW1zX3JlYyRzdW1tYXJ5Wyhuc3ViKjQrMSk6KG5zdWIqNSksMV0pCgojIGRpdmlkZSBiZXRhIGludG8gdGhlIHR3by4uLgoKIyMgcCBpcyAxLCBzbyB0aGUgb2RkIHJvd3MKYmV0YV9wX3JlYyA8LSBkYXRhLmZyYW1lKGJldGFfYWxsX3JlY1sgYyhUUlVFLEZBTFNFKSwgXSkgIyBvZGQgcm93cwpiZXRhX21fcmVjIDwtIGRhdGEuZnJhbWUoYmV0YV9hbGxfcmVjWyAhYyhUUlVFLEZBTFNFKSwgXSkgIyBldmVuIHJvd3MKCm5hbWVzKGFscGhhX2VzdF9yZWMpIDwtICJhbHBoYSIKbmFtZXMoYmV0YV9wX3JlYykgPC0gImJldGFfcGx1cyIKbmFtZXMoYmV0YV9tX3JlYykgPC0gImJldGFfbWludXMiCm5hbWVzKGxhbWJkYV9yZWMpIDwtICJsYW1iZGEiCiAgCgpgYGAKCiMjIyMgQ29ycmVsYXRlIGFjdHVhbCByYXRpbmdzIHdpdGggc2ltdWxhdGVkIHJhdGluZ3MKCnVzZSB0aGUgc2ltdWxhdGVkIHJhdGluZ3MgcGVyIHBlcnNvbiB0aGF0IHdlIGhhdmUgZGVyaXZlZCB1c2luZyBvdXIgcGFyYW1ldGVycyBhbmQgc2VlIGhvdyB3ZWxsIHRoZXkgYWxpZ24gd2l0aCB0aGUgcmVhbCByYXRpbmdzLi4uCgpPbmx5IHNob3dpbmcgdGhlIGRpYWdhbm9scyBmcm9tIGNvcnIudGVzdCBwYWNrYWdlIGhlcmUgdG8gZ2V0IHRoZSBpbXBvcnRhbnQgdDEgeCB0MSBldGMgdmFsdWVzLgoKYGBge3J9CgpwcmludCgib3JpZ2luYWwgd2l0aCByZWNvdmVyZWQ6IEFMUEhBIikKZGlhZyhjb3JyLnRlc3QoYWxwaGFfZXN0X3JlYyxhbHBoYV9lc3QpJHIpCgpwcmludCgib3JpZ2luYWwgd2l0aCByZWNvdmVyZWQ6IEJFVEEgUExVUyIpCmRpYWcoY29yci50ZXN0KGJldGFfcF9yZWMsYmV0YV9wKSRyKQoKcHJpbnQoIm9yaWdpbmFsIHdpdGggcmVjb3ZlcmVkOiBCRVRBIE1JTlVTIikKZGlhZyhjb3JyLnRlc3QoYmV0YV9tX3JlYyxiZXRhX20pJHIpCgpwcmludCgib3JpZ2luYWwgd2l0aCByZWNvdmVyZWQ6IExBTUJEQSIpCmRpYWcoY29yci50ZXN0KGxhbWJkYV9yZWMsbGFtYmRhKSRyKQoKYGBgCgpJbnRlcmVzdGluZ2x5IHRoaXMgaXMgbXVjaCB3b3JzZSBmb3IgdGhlIGxhbWJkYS4gQWxzbyBub3QgZ3JlYXQgZm9yIGJldGEuIE9ubHkgYWxwaGEgcmVtYWlucyBvay4gU28gb3ZlcmFsbCB0aGUgMSBiZXRhIGlzIHByb2JhYmx5IGJldHRlciBldmVuIHRob3VnaCB0aGUgQklDIGlzICpzbGlnaHRseSogd29yc2UuCgojIER1YWwgbGVhcm5pbmcgCgojIyBNb2RlbCAxMDogZHVhbCBsZWFybmluZyArIHB1bmlzaG1lbnQgc2Vuc2l0aXZpdHkgKCAxIGJldGEpCgphIGxhIFRvYnkgcGFwZXIgLSBkdWFsIGxlYXJuaW5nIG1vZGVsLgoKQWxsb3dzIHRoZSBzdGltdWxpIHRvIHVwZGF0ZSBiYXNlZCBvbiB0aGUgb3RoZXIgc3RpbXVsdXMgb3V0Y29tZXMuCgpUaGlzIHZlcnNpb24gYWxzbyBpbmNsdWRlcyB0aGUgcHVuaXNobWVudCBzZW5zaXRpdml0eSBtdWx0aXBsaWVyIGFzIHRoaXMgd2FzIGJlc3Qgc28gZmFyCgoKIyMjIE1vZGVsCgpgYGB7ciBkdWFsIGxlYXJuIHNldCB1cH0KI3NjcmlwdApzdGFubmFtZT0nYmV0YV9EdWFsTGVhcm5fUHVuU2Vuc18xYmV0YS5zdGFuJwoKYGBgCgoKYGBge3IgZHVhbCBsZWFybn0KCmZsYXJlX2ZpdCA8LSBtb2RlbF9ydW4oJ21pbicsc3Rhbm5hbWUsZmxhcmVfZGF0YSkKCiMjIGdldCBzb21lIGJhc2ljIG91dHB1dCBkZXNjcmlwdGlvbnMgcHJpbnRlZCB0byBzY3JlZW4Kb3V0X2Rlc2NyaWJlKGZsYXJlX2ZpdCxuc3ViKQoKIyBleHRyYWN0IGZpdCBkYXRhCnN1bW1hcnlfZmxhcmUgPC0gc3VtbWFyeShmbGFyZV9maXQpCgpgYGAKCgojIyMjIENyZWF0ZSBCSUMgZnJvbSBsb2cgbGlrZWxpaG9vZAoKYGBge3J9CiMjIGV4dHJhY3QgbG9nIGxpa2VsaWhvb2QKCmZsYXJlX2xvZ2xpa2UgPC0gZXh0cmFjdF9sb2dfbGlrKGZsYXJlX2ZpdCwgcGFyYW1ldGVyX25hbWUgPSAibG9nbGlrIiwgbWVyZ2VfY2hhaW5zID0gVFJVRSkKCiNjYWxjdWxhdGUgQklDCgpGTEFSZV9iaWM8LWJpYyhudHJpYWxzLC1jb2xNZWFucyhmbGFyZV9sb2dsaWtlKSwyKSAjbnVtYmVyIG9mIHBhcmFtZXRlcnMgaW4gdGhhdCBtb2RlbCBlLmcuIDQpCgojIyBtZWFuIEJJQyBhcyBtb2RlbCBjb21wYXJpc29ucyB0b29sOgoKcHJpbnQoIk1lYW4gQmF5ZXNpYW4gaW5mb3JtYXRpb24gY3JpdGVyaW9uIGZvciBtb2RlbCIpCgptZWFuKEZMQVJlX2JpYykKCmBgYAoKIyMjIyBBZGQgdG8gYmFyIHBsb3QKCmBgYHtyfQoKbW9kX2NvbXAgPC0gcmJpbmQobmEub21pdChtb2RfY29tcCksYygiRHVhbCBMZWFybmluZyIsbWVhbihGTEFSZV9iaWMpKSkKCm1vZF9jb21wJEJJQyA8LSBvZHAoYXMubnVtZXJpYyhtb2RfY29tcCRCSUMpKQoKbW9kX2NvbXAgPC0gYXMuZGF0YS5mcmFtZShuYS5vbWl0KG1vZF9jb21wKSkKCgojIyBwbG90IGZ1bmN0aW9uIC0gY3JlYXRlIHBsb3QKcGxvdF9tb2RlbHMobW9kX2NvbXApCgpgYGAKCgoKIyBSYXRpbmcgY29uc2lzdGVuY3kKCkEgcGFyYW1ldGVyIHRoYXQgcmVwcmVzZW50cyB0aGUgcmF0aW5nIGNvbnNpc3RlbmN5IGZvciBtdWx0aXBsZSByZXBlYXRlZCAvIHNpbWlsYXIgdHJpYWxzLiBJIHRoaW5rIGl0IHdvdWxkIGJlIGJlc3QgdG8gaGF2ZSBvbmUgZWFjaCBmb3IgdGhlIENTKyBhbmQgQ1MtIGdpdmVuIHRoZXNlIGRpZmZlciBpbiB0ZXJtcyBvZiBob3cgc2ltaWxhciB0aGUgdHJpYWxzIGFyZSAoQ1MtIGlzIGFsd2F5cyB1bi1lbmZvcmNlZCBmb3IgZXhhbXBsZSkuIENhbiBpbWFnaW5lIGNvbnNpc3RlbmN5IGlzIGEgcGFyYW1ldGVyIHRoYXQgaXMgY29uY2lzdGVudCByZWdhcmRsZXNzIG9mIHJlaW5mb3JjZW1lbnQgLyBzdGltdWx1cyB0eXBlIHRob3VnaCwgZXNwZWNpYWxseSBpbiBsYXRlciBwaGFzZXMuIFNvIHdvcnRoIHRlc3RpbmcgYm90aCBtb2RlbHMuCgpBIHNpbWlsYXIgcGFyYW1ldGVyIGlzIFt1c2VkIGluIHRoZSBjaGFycGVudGllciBldCBhbC4gcGFwZXJdKGh0dHBzOi8vZjEwMDAuY29tL3dvcmsvaXRlbS82NzA3MTM0L3Jlc291cmNlcy81ODY0Nzc0L3BkZikgKHNlZSB0aGUgbGFzdCBwYWdlIGJlZm9yZSB0aGUgcmVmZXJlbmNlcykuCgpXZSB3aWxsIGVzdGltYXRlIHRoaXMgcGFyYW1ldGVyIGFzIGEgZmFjdG9yIHRoYXQgaW5mbHVlbmNlcyB0aGUgb3ZlcmFsbCBzaGFwZSBvZiB0aGUgY2hvaWNlIHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbiAoYmV0YSBkaXN0cmlidXRpdW9uKS4gSXQgd2lsbCBkbyB0aGlzIHZpYSB0aGUgc3VmZmljaWVudCBwYXJhbWV0ZXJzIHRoYXQgYXJlIGluZmx1ZW5jZXMgYnkgc3RpbXVsdXMgdmFsdWUgZXRjIHBlciB0cmlhbC4KCioqbm90ZSB2ZXJ5IHVuc3VyZSBhYm91dCB0aGlzIC0gbmVlZCB0byBjaGVjayBpdCBvdXQgd2l0aCBBbGV4KioKCiQkc2hhcGUxKHN0aW11bHVzKSA9ICgxICsgZXhwKC1cbXUgKiBWUGx1c1t0LHBdICogKChWUGx1c1t0LHBdICogKDEtVlBsdXNbdCxwXSkpIC8gYmV0YVtwLDFdKSleLTEgJCQKd2hlcmUgJCRcbXUgPSBsb2dpdFxcc2Vuc2l0aXZ0eSQkCgpXaGVyZSBsb2dpdCBzZW5zaXRpdml0eSBlZmZlY3RpdmVseSBtZWFucyBjb25zaXN0ZW5jeSBvZiByYXRpbmcgY29uc2lzdGVuY3k7IGhpZ2hlciB2YWx1ZWQgc2hvdWxkIG1lYW4gZ3JlYXRlciBjb25zaXN0ZW5jeS4KCgojIyMgTW9kZWwKCmBgYHtyIGNvbnNpc3RlbmN5IHNldCB1cH0KI3NjcmlwdApzdGFubmFtZT0nYmV0YV9tZWFuMWJldGFfQ29uc2lzdGVuY3kuc3RhbicKCmBgYAoKCmBgYHtyIGNvbnNpc3RlbmN5fQoKZmxhcmVfZml0IDwtIG1vZGVsX3J1bignbWluJyxzdGFubmFtZSxmbGFyZV9kYXRhKQoKIyMgZ2V0IHNvbWUgYmFzaWMgb3V0cHV0IGRlc2NyaXB0aW9ucyBwcmludGVkIHRvIHNjcmVlbgpvdXRfZGVzY3JpYmUoZmxhcmVfZml0LG5zdWIpCgojIGV4dHJhY3QgZml0IGRhdGEKc3VtbWFyeV9mbGFyZSA8LSBzdW1tYXJ5KGZsYXJlX2ZpdCkKCmBgYAoKCkJJQyBpcyB0ZXJyaWJsZQoKCiMjIyMgQ3JlYXRlIEJJQyBmcm9tIGxvZyBsaWtlbGlob29kCgpgYGB7cn0KIyMgZXh0cmFjdCBsb2cgbGlrZWxpaG9vZAoKZmxhcmVfbG9nbGlrZSA8LSBleHRyYWN0X2xvZ19saWsoZmxhcmVfZml0LCBwYXJhbWV0ZXJfbmFtZSA9ICJsb2dsaWsiLCBtZXJnZV9jaGFpbnMgPSBUUlVFKQoKI2NhbGN1bGF0ZSBCSUMKCkZMQVJlX2JpYzwtYmljKG50cmlhbHMsLWNvbE1lYW5zKGZsYXJlX2xvZ2xpa2UpLDIpICNudW1iZXIgb2YgcGFyYW1ldGVycyBpbiB0aGF0IG1vZGVsIGUuZy4gNCkKCiMjIG1lYW4gQklDIGFzIG1vZGVsIGNvbXBhcmlzb25zIHRvb2w6CgpwcmludCgiTWVhbiBCYXllc2lhbiBpbmZvcm1hdGlvbiBjcml0ZXJpb24gZm9yIG1vZGVsIikKbWVhbihGTEFSZV9iaWMpCgpgYGAKCiMjIyMgQWRkIHRvIGJhciBwbG90CgpgYGB7cn0KCm1vZF9jb21wIDwtIHJiaW5kKG5hLm9taXQobW9kX2NvbXApLGMoIkNvbnNpc3RlbmN5IixtZWFuKEZMQVJlX2JpYykpKQoKCm1vZF9jb21wJEJJQyA8LSBvZHAoYXMubnVtZXJpYyhtb2RfY29tcCRCSUMpKQoKbW9kX2NvbXAgPC0gYXMuZGF0YS5mcmFtZShuYS5vbWl0KG1vZF9jb21wKSkKCgojIyBwbG90IGZ1bmN0aW9uIC0gY3JlYXRlIHBsb3QKcGxvdF9tb2RlbHMobW9kX2NvbXApCgpgYGAKCgojIEdlbmVyYWxpc2F0aW9uCgojIE5PVEUgVE8gU0VMRjo6CgptYXliZSBnZW5lcmFsaXNlIHRoZSBwcmVkaWN0aW9uIGVycm9yIE5PVCB0aGUgdmFsdWUgKHNvIGFkZCBzb21lIG9kIGRlbHRhUCB0byB0aGUgVk1pbnVzIGNhbGN1bGF0aW9uLi4uLikKCiMjIHNvbWUgaW50cm8KCkJhc2ljYWxseSBoZXJlIHdlIHdhbnQgdG8gY2FwdHVyZSBhIHBhcmFtZXRlciB0aGF0IGVzdGltYXRlcyBob3cgbXVjaCB0aGUgbGVhcm5pbmcgZnJvbSB0aGUgcmVpbmZvcmNlZCBzdGltdWx1cyBpbmZsdWVuY2VzIHJlc3BvbnNlcyB0byB0aGUgJ3NhZmUnIHN0aW11bHVzLgoKQmFzaW5nIG15IGZpcnN0IGVmZm9ydCBvbiBbTm9yYnVyeSwgUm9iYmlucyAmIFNleW1vdXIsIDIwMThdKGh0dHBzOi8vZjEwMDAuY29tL3dvcmsvaXRlbS81MjQzNDE5L3Jlc291cmNlcy82MDM4MDM5L3BkZiksIGFuZCB0aGVpciBmaW5kaW5nIHRoYXQgdGhlcmUgaXMgZ2VuZXJhbGlzYXRpb24gYmFzZWQgb24gdmFsdWUgYW5kIHBlcmNlcHR1YWwgcHJvY2Vzc2VzLgoKRnJvbSB0aGVpciBhYnN0cmFjdCAKCj4+ICJXZSBmb3VuZCB0aGF0IGdlbmVyYWxpemF0aW9uIG9mIGF2b2lkYW5jZSBjb3VsZCBiZSBwYXJzZWQgaW50byBwZXJjZXB0dWFsIGFuZCB2YWx1ZS1iYXNlZCBwcm9jZXNzZXMsIGFuZCBmdXJ0aGVyLCB0aGF0IHZhbHVlLWJhc2VkIGdlbmVyYWxpemF0aW9uIGNvdWxkIGJlIHN1YmRpdmlkZWQgaW50byB0aGF0IHJlbGF0aW5nIHRvIGF2ZXJzaXZlIGFuZCBuZXV0cmFsIGZlZWRiYWNrIi4uLi4gIkZ1cnRoZXIsIGdlbmVyYWxpemF0aW9uIGZyb20gYXZlcnNpdmUsIGJ1dCBub3QgbmV1dHJhbCwgZmVlZGJhY2sgd2FzIGFzc29jaWF0ZWQgd2l0aCBzZWxmLXJlcG9ydGVkIGFueGlldHkgYW5kIGludHJ1c2l2ZSB0aG91Z2h0cy4gVGhlc2UgcmVzdWx0cyByZXZlYWwgYSBzZXQgb2YgZGlzdGluY3QgbWVjaGFuaXNtcyB0aGF0IG1lZGlhdGUgZ2VuZXJhbGl6YXRpb24gaW4gYXZvaWRhbmNlIGxlYXJuaW5nLCBhbmQgc2hvdyBob3cgc3BlY2lmaWMgaW5kaXZpZHVhbCBkaWZmZXJlbmNlcyB3aXRoaW4gdGhlbSBjYW4geWllbGQgYW54aWV0eS4gIgoKZnJvbSBpbnRyb2R1Y3Rpb24KCj4+ICJJdCBpcyB0aGVyZWZvcmUgcG9zc2libGUgdGhhdCB1bmRlci1nZW5lcmFsaXphdGlvbiBvZiBzYWZldHkgY3VlcywgYXMgb3Bwb3NlZCB0byBvdmVyLWdlbmVyYWxpemF0aW9uIG9mIGF2ZXJzaXZlIGN1ZXMsIG1pZ2h0IGJlIGEgY29udHJpYnV0aW5nIGZhY3RvciB0byBzdXNjZXB0aWJpbGl0eSB0byBkaXNvcmRlcnMgc3VjaCBhcyBnZW5lcmFsaXplZCBhbnhpZXR5IgoKCiMjIEVxdWF0aW9ucwoKSSB3aWxsIGJhc2ljYWxseSByZXBsaWNhdGUgdGhlIHZpc3VhbCBhbmQgdmFsdWUgZ2VuZXJhbGlzYXRpb24gZXF1YXRpb25zLgoKIyMjIFZpc3VhbCAoaS5lLiBwb3NzaWJsZSBpZGVudGlmeSBjb25mdXNpb24gb3ZlciB0aGUgdHdvIHN0aW11bGkpOgoKJCRWX2MsX20gPTAuODAqVl9DLF9tICsgMC4yMCpWX0MsX3AkJAoKCgoKIyMjIFZhbHVlOgoKJCRHX3MgPSAxL2V4cChccmhvX28pXjIgLyAyKlxkZWx0YSkpJCQKd2hlcmUgJF9zJCBpcyBjdXJyZW50IHN0aW11bHVzLCBhbmQgJF9vJCBpcyB0aGUgb3RoZXIgc3RpbXVsdXMuICRccmhvJCBpcyB0aGUgcGFyYW1ldGVyIGdvdmVybmluZyBzaGFwZSAnc3Bpa2luZXNzJyIgJFxkZWx0YSQgaXMgYSBmcmVlIHBhcmFtZXRlciB0aGF0IGdvdmVybnMgdGhlIHdpZHRoIG9mIHRoZSBHYXVzc2lhbiBmdW5jdGlvbiB0aGF0IGdvdmVybnMgZ2VuZXJhbGlzYXRpb24uIFRoaXMgcGFyYW1ldGVyIHNob3VsZCBwcm9iYWJseSBkaWZmZXIgZGVwZW5kaW5nIG9uIHRyaWFsIG91dGNvbWUgKHNjcmVhbSBvciBuZXV0cmFsKSAkXGRlbHRhX3MkIGFuZCAkXGRlbHRhX24kLiAKClRoZXkgYXV0aG9ycyB1cGRhdGUgdGhlaXIgdmFsdWUgYnkgbXVsdGlwbHlpbmcgaXQgYnkgdGhlIGdlbmVyYWxpc2F0aW9uIG9mIHRoZSBjdXJyZW50ICdzdGF0ZScgKHN0aW11bHVzKS4gaS5lLiAkKkdfcyQgYXMgdGhlIGxhc3QgdGVybS4gCgpGaXJzdCB3ZSB3aWxsIHVzZSBhIHNpbmdsZSAkXGRlbHRhJCB2YWx1ZSwgcmF0aGVyIHRoYW4gdXBkYXRpbmcgcGVyIHRyaWFsIGRlcGVuZGluZyBvbiBpZiBpdCBpcyBzY3JlYW0gKyBvciAtCgoKU28sIGZvciBvdXJzIHRoZSBmb2xsb3dpbmcgd2lsbCBiZSBhZGRlZCB0byB0aGUgcHVuaXNobWVudCBzZW5zaXRpdml0eSBzaW5nbGUgYmV0YSBtb2RlbC4KCiMjIyBPbmUgZ2VuZXJhbGlzYXRpb24gcGFyYW1ldGVyCgpHZW5lcmFsaXNhdGlvbjoKCiQkRyA9IDEvZXhwKChccmhvX20gLSBccmhvX3ApXjIgLyAoMipcZGVsdGFeMikpJCQKCiMjIyBnZW5lcmFsaXNhdGlvbiBwZXIgc3RpbXVsdXMKCkdlbmVyYWxpc2F0aW9uIHBsdXM6CgokJEdfcCA9IDEvZXhwKChccmhvX20gLSBccmhvX3ApXjIgLyAoMipcZGVsdGFeMikpJCQKCkdlbmVyYWxpc2F0aW9uIG1pbnVzOgoKJCRHX20gPSAxL2V4cCgoXHJob19wIC0gXHJob19tKV4yIC8gKDIqXGRlbHRhXjIpKSQkClZhbHVlIHBsdXM6CgokJFZQbHVzW3QrMSxwXT1WUGx1c1t0LHBdK2FscGhhW3BdKlByZWRFcnJvclBsdXNbdCxwXSpHX3AkJApWYWx1ZSBtaW51czoKCiQkVk1pbnVzW3QrMSxwXT1WTWludXNbdCxwXSthbHBoYVtwXSpQcmVkRXJyb3JNaW51c1t0LHBdKkdfcCQkCgoKIyMjIGFkZGl0aW9uYWwgdGhpbmdzIHRvIHRyeToKCiMjIyMgZGVwZW5kZW5jZSBvbiBwcmVkaWN0aW9uIGVycm9yCgokXGthcHBhJCB3aWxsIGJlIGEgZnJlZSBwYXJhbWV0ZXIgdGhhdCBpbmRpY2F0ZXMgZGlmZmVyZW5jZSBpbiBkZXBlbmRlbmNlIG9uIHByZWRpY3Rpb24gZXJyb3IgaGlzdG9yeSwgYW5kIHdpbGwgbWFrZSB0aGUgdiB1cGRhdGVzIGxpa2Ugc286CgoKVmFsdWUgcGx1czoKCiQkVlBsdXNbdCsxLHBdPVZQbHVzW3QscF0rXGthcHBhKmFscGhhW3BdKlByZWRFcnJvclBsdXNbdCxwXSpHX3AkJApWYWx1ZSBtaW51czoKCiQkVk1pbnVzW3QrMSxwXT1WTWludXNbdCxwXStca2FwcGEqYWxwaGFbcF0qUHJlZEVycm9yTWludXNbdCxwXSpHX3AkJAoKIyMjIyB1cGRhdGluZyBsZWFybmluZyByYXRlIHBlciB0cmlhbCwgcGVyIHN0aW11bHVzCgp0aGUgYWxwaGEgd291bGQgYmVjb21lCgokJFxhbHBoYV90KzEgPSBcZXRhICB8ICAoUHJlZEVycm9yLVZfcCxfdCl8ICsgKDEtXGV0YSkqXGFscGhhX3QkJAoKCiMjIE1vZGVsIDExOiBWaXN1YWwgZ2VuZXJhbGlzYXRpb24KCgoKQWxsb3cgdmlzdWFsIGdlbmVyYWxpc3Rpb24gYmV0d2VlbiB0byBjaGFuZ2UgdGhlIHZhbHVlIG9mIHRoZSBzdGltdWxpIHBlciB0cmlhbC4KCk11bHRpcGx5IG93biB2YWx1ZSBieSAuOCBhbmQgYWRkIHRoZSBvdGhlciBzdGltdWxpIHZhbHVlIG9mIC4yIChzZWUgZXF1YXRpb25zIGFib3ZlKS4KCiMjIyBNb2RlbAoKYGBge3IgdmlzIGdlbiBzZXQgdXB9CiNzY3JpcHQKc3Rhbm5hbWU9J2JldGFfVmlzdWFsX0dlbi5zdGFuJwoKYGBgCgoKYGBge3IgdmlzIGdlbn0KCmZsYXJlX2ZpdCA8LSBtb2RlbF9ydW4oJ21pbicsc3Rhbm5hbWUsZmxhcmVfZGF0YV9ub2xvZykKCiMjIGdldCBzb21lIGJhc2ljIG91dHB1dCBkZXNjcmlwdGlvbnMgcHJpbnRlZCB0byBzY3JlZW4Kb3V0X2Rlc2NyaWJlKGZsYXJlX2ZpdCxuc3ViKQoKIyBleHRyYWN0IGZpdCBkYXRhCnN1bW1hcnlfZmxhcmUgPC0gc3VtbWFyeShmbGFyZV9maXQpCgpgYGAKCgojIyMjIENyZWF0ZSBCSUMgZnJvbSBsb2cgbGlrZWxpaG9vZAoKYGBge3J9CiMjIGV4dHJhY3QgbG9nIGxpa2VsaWhvb2QKCmZsYXJlX2xvZ2xpa2UgPC0gZXh0cmFjdF9sb2dfbGlrKGZsYXJlX2ZpdCwgcGFyYW1ldGVyX25hbWUgPSAibG9nbGlrIiwgbWVyZ2VfY2hhaW5zID0gVFJVRSkKCiNjYWxjdWxhdGUgQklDCgpGTEFSZV9iaWM8LWJpYyhudHJpYWxzLC1jb2xNZWFucyhmbGFyZV9sb2dsaWtlKSwyKSAjbnVtYmVyIG9mIHBhcmFtZXRlcnMgaW4gdGhhdCBtb2RlbCBlLmcuIDQpCgojIyBtZWFuIEJJQyBhcyBtb2RlbCBjb21wYXJpc29ucyB0b29sOgoKcHJpbnQoIk1lYW4gQmF5ZXNpYW4gaW5mb3JtYXRpb24gY3JpdGVyaW9uIGZvciBtb2RlbCIpCgptZWFuKEZMQVJlX2JpYykKCmBgYAoKIyMjIyBBZGQgdG8gYmFyIHBsb3QKCmBgYHtyfQoKbW9kX2NvbXAgPC0gcmJpbmQobmEub21pdChtb2RfY29tcCksYygiVmlzdWFsIEdlbmVyYWxpc2F0aW9uIixtZWFuKEZMQVJlX2JpYykpKQoKbW9kX2NvbXAkQklDIDwtIG9kcChhcy5udW1lcmljKG1vZF9jb21wJEJJQykpCgptb2RfY29tcCA8LSBhcy5kYXRhLmZyYW1lKG5hLm9taXQobW9kX2NvbXApKQoKCiMjIHBsb3QgZnVuY3Rpb24gLSBjcmVhdGUgcGxvdApwbG90X21vZGVscyhtb2RfY29tcCkKCmBgYAoKIyBhdm9pZGFuY2UKClVzaW5mIHZvbHVtZSBwZXIgdHJpYWwgYXMgYW4gYXZvaWRhbmNlIG91dGNvbWUgYW5kIG1vZGVsbGluZyBhcyBwZXIgW05vcmJ1cnkgZXQgYWxdKGh0dHBzOi8vZjEwMDAuY29tL3dvcmsvaXRlbS81MjQzNDE5L3Jlc291cmNlcy82MDM4MDM5L3BkZikgaW4gYSBzb3J0IG9mIGRpZmZ1c2lvbiBkcmlmdCB3YXkuIEJhc2ljYWxseSB1cGRhdGluZyB2YWx1ZSBvZiBhdm9pZCBvciBub3QgYXZvaWRpbmcgd2hlcmUgYXZvaWQgPSA9IHZvbHVtZSBkb3duIHBlciB0cmlhbC4KCk1pZ2h0IHdhbnQgdG8gdXNlIGEgUGVhcmNlLUhhbGwgYXNzb2NpYXRiaWxpdHkgcnVsZSB0byB1cGRhdGUgdGhlIGxlYXJuaW5nIHJhdGUgIGhlcmUuLi4KCj4+ICJBY2NvcmRpbmcgdG8gdGhpcyBydWxlLCB0aGUgbGVhcm5pbmcgcmF0ZSBvbiBlYWNoIHRyaWFsIGlzIGRldGVybWluZWQgYnkgdGhlIGFic29sdXRlIG1hZ25pdHVkZSBvZiBwYXN0IHByZWRpY3Rpb24gZXJyb3JzLCBzdWNoIHRoYXQgc3RhdGUtYWN0aW9uIHZhbHVlIGVzdGltYXRlcyBhcmUgdXBkYXRlZCBieSBtb3JlIHdoZW4gcHJldmlvdXMgb3V0Y29tZXMgaGF2ZSBiZWVuIG1vcmUgc3VycHJpc2luZywgYW5kIGJ5IGxlc3Mgd2hlbiB0aGV5IHdlcmUgbGVzcyBzdXJwcmlzaW5nLiBUaGlzIGFsbG93cyBmb3IgbGVhcm5pbmcgaW4gdGVybXMgb2YgbW9kZWxsZWQgdmFsdWUgYWRqdXN0bWVudCB0byBiZSBncmVhdGVyIHdoZW4gb3V0Y29tZXMgYXJlIG1vcmUgc3VycHJpc2luZyAoZS5nLiBhdCB0aGUgc3RhcnQgb2YgdGhlIHRhc2spLCBidXQgdG8gYmUgbGVzc2VyIChsZWFkaW5nIHRvIG1vcmUgc3RhYmxlIHZhbHVlcykgd2hlbiBvdXRjb21lcyBhcmUgYmV0dGVyIHByZWRpY3RlZC4gQSBub24tY29uc3RhbnQgbGVhcm5pbmcgcmF0ZSBhbHNvIGVuc3VyZXMgdGhhdCBwYXJhbWV0ZXJzIGdvdmVybmluZyB3aWR0aCBvZiB2YWx1ZS1iYXNlZCBnZW5lcmFsaXphdGlvbiwgd2hpY2ggYXJlIGFzc3VtZWQgdG8gYmUgY29uc3RhbnQgb3ZlciB0aGUgY291cnNlIG9mIHRoZSB0YXNrLCBhcmUgaWRlbnRpZmlhYmxlIGR1cmluZyBwYXJhbWV0ZXIgZXN0aW1hdGlvbiAoc2VlIGJlbG93IGVxdWF0aW9ucykuIgoKCiMgRm9yZ2V0dGluZwoKdGhpcyBwYXJhbWV0ZXIgaXMgaG93IG11Y2ggdGhleSByZXRhaW4gd2hhdCB0aGV5IGxlYXJuZWQgb3ZlciBwcmV2aW91cyB0cmlhbHMgYW5kIHVzZSBpdCB0byBpbmZvcm0gdGhlIGN1cnJlbnQgcmF0aW5nLgoKCgoKIyB0byBkbwoKKmludmVzdGlndGUgY2hhbmdlIHBvaW50IGRldGVjdGlvbiBwYXJhbWV0ZXJzICh3aGVuIHJlaW5mb3JjZW1lbnQgY2hhbmdlcyAtIGkuZS4gbW92aW5nIGFjcXVpc2l0aW9uIHRvIGV4dGluY3Rpb24pCiAgKiBjb3VsZCBkbyB0aGlzIG9yIG1vZGVsIHRoZSBwaGFzZXMgc2VwYXJhdGVseSAtIGNoZWNrIHdoaWNoIGJlc3QgZml0cwogIAoqYWRkIHByaW9ycyEgVGhlc2UgYXJlIHdoYXQgeW91IGV4cGVjdCB0aGUgZ3JvdXAgdG8gbG9vayBsaWtlIChpLmUgYWxwaGEgaXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgYXJvdW5kIGEgbWVhbiBvZiAwLjUgd2l0aCB2YXJpYW5jZSBvZiAxMCBvciBzb21ldGhpbmcpCipMT09LVVAgUiBzdGFuIGNob2ljZSBvZiBwcmlvcnMuCiogY2FuIGhhdmUgaW5mb3JtYXRpdmUgb3IgdW5pbmZvcm1hdGl2ZSBwcmlvcnMgKGkuZS4gYWdub3N0aWMgb3Igbm90KQoKKiBBdm9pZGFuY2UgYXMgdm9sdW1lIHJlZHVjdGlvbnMKCiogQWRkIHBhcmFtZXRlcnMKCiogRE8gTk9UIEZPUkdFVCBUTyBNQUtFIFNVUkUgV0UgSEFWRSBBTiBBQ0NVUkFURSBTQ1JFQU0gUEFUVEVSTiBQRVIgUEVSU09OIEZPUiBDUysgSU4gQUNRVUlTSVRJT04KCgoKIyBQdXNoIGFueSB1cGRhdGVzIHRvIGdpdGh1YiAKCiMjIyMjIEFueSBwdXNoIHRoZSB1cGRhdGVzIHRvIGdpdGh1YgoKVW5oYXNoIHRoZSBzZXJpZXMgYmVsb3cgaWYgeW91IG1hZGUgYW55IGNoYW5nZXMuCgoKYGBge2Jhc2h9CgojIyBpbml0aWFsaXNlIGJhc2ggZGlyZWN0b3J5IGFuZCBmaWxlbmFtZQpzdGFubmFtZT0icHVuaXNoX29ubHkuc3RhbiIKc2NyaXB0ZGlyPSIvVXNlcnMva2lyc3Rpbi9Ecm9wYm94L1NHRFAvRkxBUmUvRkxBUmVfTUFTVEVSL1Byb2plY3RzL0hpZXJhY2hhbF9tb2RlbGxpbmcvU2NyaXB0cyIKCgojIyBzdGFnZQojZ2l0IGFkZCAkc2NyaXB0ZGlyLyRzdGFubmFtZQoKCiMjIHB1c2ggCgojZ2l0IHB1c2ggQmF5ZXNfbW9kZWxsaW5nIAoKCmBgYAoKCgoKCgo=